diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..659ab3d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +src/ +pkg/ +zshell/ +*.tar.* diff --git a/PKGBUILD b/PKGBUILD index 0f877bf..f07fd45 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -8,7 +8,7 @@ license=('GPL-3.0-only') depends=('python' 'python-pillow' 'python-materialyoucolor' 'libnotify' 'swappy' 'dart-sass' 'app2unit' 'wl-clipboard' 'dconf' 'cliphist' 'python-typer') makedepends=('python-build' 'python-installer' 'python-hatch' 'python-hatch-vcs') -source=("$pkgname::git+$url.git#branch=cli-tool") +source=("$pkgname::git+$url.git#branch=settingsWindow") sha256sums=('SKIP') build() { diff --git a/pkg/zshell/.BUILDINFO b/pkg/zshell/.BUILDINFO new file mode 100644 index 0000000..24fde8a --- /dev/null +++ b/pkg/zshell/.BUILDINFO @@ -0,0 +1,2420 @@ +format = 2 +pkgname = zshell +pkgbase = zshell +pkgver = 0.1.0-1 +pkgarch = any +pkgbuild_sha256sum = 67ab70292f9059b78ee4f7c6a6b233b4a38d131a0ff8eba76677ba107e51c15f +packager = Unknown Packager +builddate = 1771871772 +builddir = /home/zach/GitProjects/zshell-PKGBUILD +startdir = /home/zach/GitProjects/zshell-PKGBUILD +buildtool = makepkg +buildtoolver = 7.1.0 +buildenv = !distcc +buildenv = color +buildenv = !ccache +buildenv = check +buildenv = !sign +options = strip +options = docs +options = !libtool +options = !staticlibs +options = emptydirs +options = zipman +options = purge +options = !debug +options = lto +options = !autodeps +installed = 64gram-desktop-bin-1:1.1.94-1-x86_64 +installed = 64gram-desktop-bin-debug-1:1.1.93-1-x86_64 +installed = 7zip-26.00-1.1-x86_64_v3 +installed = a52dec-0.8.0-2.1-x86_64 +installed = aalib-1.4rc5-19.1-x86_64_v3 +installed = abseil-cpp-20250814.1-1.1-x86_64_v3 +installed = accounts-qml-module-0.7-6.1-x86_64 +installed = accountsservice-23.13.9-3.1-x86_64_v3 +installed = acl-2.3.2-1.1-x86_64 +installed = ada-3.4.2-2.1-x86_64_v3 +installed = adriconf-2.7.3-2.1-x86_64_v3 +installed = adwaita-cursors-49.0-1-any +installed = adwaita-fonts-49.0-2-any +installed = adwaita-icon-theme-49.0-1-any +installed = adwaita-icon-theme-legacy-46.2-3-any +installed = ags-hyprpanel-git-r626.0e73df1-1-x86_64 +installed = aha-0.5.1-3.1-x86_64 +installed = aj-snapshot-0.9.9-3.1-x86_64 +installed = akonadi-25.12.2-1.1-x86_64_v3 +installed = akonadi-calendar-25.12.2-1.1-x86_64_v3 +installed = akonadi-contacts-25.12.2-1.1-x86_64_v3 +installed = akonadi-mime-25.12.2-1.1-x86_64_v3 +installed = akonadi-search-25.12.2-1.1-x86_64_v3 +installed = alacritty-0.16.1-1.1-x86_64_v3 +installed = alsa-card-profiles-1:1.4.10-2.1-x86_64_v3 +installed = alsa-lib-1.2.15.3-2.1-x86_64_v3 +installed = alsa-plugins-1:1.2.12-5.1-x86_64_v3 +installed = alsa-topology-conf-1.2.5.1-4-any +installed = alsa-ucm-conf-1.2.15.3-1-any +installed = alsa-utils-1.2.15.2-2.1-x86_64_v3 +installed = ananicy-cpp-1.1.1-10.1-x86_64_v3 +installed = angrysearch-1.0.4-4-any +installed = aom-3.13.1-2.1-x86_64_v3 +installed = app2unit-1.3.0-1-any +installed = appmenu-glib-translator-git-25.04.r8.gaea4ea3-1-x86_64 +installed = appmenu-glib-translator-git-debug-25.04.r8.gaea4ea3-1-x86_64 +installed = appstream-1.1.2-1.1-x86_64_v3 +installed = appstream-qt-1.1.2-1.1-x86_64_v3 +installed = apr-1.7.6-1-x86_64 +installed = apr-util-1.6.3-2.1-x86_64 +installed = aptly-1.6.2-1-x86_64 +installed = aptly-debug-1.6.2-1-x86_64 +installed = aquamarine-0.10.0-2.1-x86_64_v3 +installed = arch-install-scripts-31-1-any +installed = archinstall-3.0.15-2-any +installed = archipelagomw-bin-0.6.6-1-x86_64 +installed = archlinux-keyring-20260206-2-any +installed = archlinux-xdg-menu-0.7.7-1-any +installed = arduino-cli-1.4.1-1.1-x86_64_v3 +installed = arduino-language-server-0.7.7-1.2-x86_64_v3 +installed = argon2-20190702-6.2-x86_64_v3 +installed = ark-25.12.2-1.1-x86_64_v3 +installed = ashell-git-r1161.845ca24-1-x86_64 +installed = asio-1.36.0-1-any +installed = assimp-6.0.4-1.1-x86_64_v3 +installed = at-3.2.5-5.1-x86_64_v3 +installed = at-spi2-core-2.58.3-1.1-x86_64_v3 +installed = atkmm-2.28.4-1.1-x86_64 +installed = attica-6.23.0-1.1-x86_64_v3 +installed = attr-2.5.2-1.1-x86_64 +installed = aubio-0.4.9-24.1-x86_64_v3 +installed = audit-4.1.2-2.1-x86_64_v3 +installed = aurorae-6.6.0-1.1-x86_64_v3 +installed = autoconf-2.72-1-any +installed = autoconf-archive-1:2024.10.16-4-any +installed = automake-1.18.1-1-any +installed = avahi-1:0.9rc3-1.1-x86_64_v3 +installed = aws-c-auth-0.9.5-1.1-x86_64_v3 +installed = aws-c-cal-0.9.13-1.1-x86_64_v3 +installed = aws-c-common-0.12.6-1.1-x86_64_v3 +installed = aws-c-compression-0.3.2-1.1-x86_64_v3 +installed = aws-c-event-stream-0.5.9-1.1-x86_64_v3 +installed = aws-c-http-0.10.10-1.1-x86_64_v3 +installed = aws-c-io-0.26.1-1.1-x86_64_v3 +installed = aws-c-mqtt-0.13.4-1.1-x86_64_v3 +installed = aws-c-s3-0.11.5-1.1-x86_64_v3 +installed = aws-c-sdkutils-0.2.4-1.1-x86_64_v3 +installed = aws-checksums-0.2.10-1.1-x86_64_v3 +installed = aws-crt-cpp-0.37.2-1.1-x86_64_v3 +installed = aws-sdk-cpp-core-1.11.749-1.1-x86_64_v3 +installed = aws-sdk-cpp-iam-1.11.749-1.1-x86_64_v3 +installed = aws-sdk-cpp-s3-1.11.749-1.1-x86_64_v3 +installed = ayatana-ido-0.10.4-1.1-x86_64 +installed = aylurs-gtk-shell-git-3.1.1.r0.ge169694-1-x86_64 +installed = aylurs-gtk-shell-git-debug-3.1.1.r0.ge169694-1-x86_64 +installed = ayugram-desktop-git-6.3.10.r3.g1f6806d-1-x86_64 +installed = babl-0.1.122-1.1-x86_64_v3 +installed = baloo-6.23.0-1.1-x86_64_v3 +installed = baloo-widgets-25.12.2-1.1-x86_64_v3 +installed = base-3-3-any +installed = base-devel-1-2-any +installed = basemark-1.2.3-6-x86_64 +installed = bash-5.3.9-2-x86_64_v3 +installed = bash-language-server-5.6.0-1-any +installed = bcg729-1.1.1-2.1-x86_64 +installed = bcprov-1.83-1-any +installed = bemoji-0.4.0-1-any +installed = bind-9.20.19-1.1-x86_64_v3 +installed = binutils-2.46-2-x86_64_v3 +installed = bison-3.8.2-8.1-x86_64 +installed = blas-3.12.1-2.1-x86_64_v3 +installed = blender-benchmark-1:3.1.0-1-x86_64 +installed = blueprint-compiler-0.18.0-2-any +installed = bluez-5.86-2.1-x86_64_v3 +installed = bluez-libs-5.86-2.1-x86_64_v3 +installed = bluez-obex-5.86-2.1-x86_64_v3 +installed = bluez-utils-5.86-2.1-x86_64_v3 +installed = bolt-0.9.10-1.1-x86_64_v3 +installed = boost-1.89.0-4.1-x86_64_v3 +installed = boost-libs-1.89.0-4.1-x86_64_v3 +installed = bootconfig-6.19-2-x86_64 +installed = botan-3.10.0-2.1-x86_64_v3 +installed = bottles-2:62.0-1-any +installed = bpf-6.19-2-x86_64 +installed = breeze-6.6.0-2.1-x86_64_v3 +installed = breeze-cursors-6.6.0-2.1-x86_64_v3 +installed = breeze-gtk-6.6.0-1-any +installed = breeze-icons-6.23.0-1.1-x86_64_v3 +installed = breeze-plymouth-6.6.0-1.1-x86_64_v3 +installed = breezy-3.3.21-2.1-x86_64_v3 +installed = brightnessctl-0.5.1-3-x86_64 +installed = brltty-6.8-6.1-x86_64_v3 +installed = brotli-1.2.0-1.1-x86_64_v3 +installed = btdu-0.7.2-1-x86_64 +installed = btop-1.4.6-1.1-x86_64_v3 +installed = btrfs-heatmap-9-4-any +installed = btrfs-progs-6.19-1-x86_64 +installed = bubblewrap-0.11.0-1.1-x86_64 +installed = buildkit-0.27.1-1.1-x86_64_v3 +installed = bzip2-1.0.8-6.1-x86_64 +installed = c-ares-1.34.6-1.1-x86_64_v3 +installed = ca-certificates-20240618-1-any +installed = ca-certificates-mozilla-3.120.1-1.1-x86_64_v3 +installed = ca-certificates-utils-20240618-1-any +installed = cabextract-1.11-2.1-x86_64 +installed = cable-0.9.28-1-any +installed = cachyos-ananicy-rules-1:1.1.23-1-any +installed = cachyos-gaming-meta-1:1.0.0-6-any +installed = cachyos-keyring-20240331-1-any +installed = cachyos-mirrorlist-22-1-any +installed = cachyos-settings-1:1.3.1-2-any +installed = cachyos-v3-mirrorlist-22-1-any +installed = cachyos-v4-mirrorlist-22-1-any +installed = caelestia-cli-1.0.4-1-any +installed = cairo-1.18.4-1.1-x86_64_v3 +installed = cairomm-1.14.5-2.1-x86_64_v3 +installed = cairomm-1.16-1.18.0-2.1-x86_64_v3 +installed = calc-2.16.1.2-1.1-x86_64_v3 +installed = capstone-5.0.7-2.1-x86_64_v3 +installed = catch2-3.13.0-1.1-x86_64_v3 +installed = cava-0.10.7-1.1-x86_64_v3 +installed = cblas-3.12.1-2.1-x86_64_v3 +installed = ccache-4.12.3-2.1-x86_64_v3 +installed = cdparanoia-10.2-9.1-x86_64 +installed = certbot-5.3.1-1-any +installed = certbot-dns-cloudflare-5.3.1-1-any +installed = certbot-nginx-5.3.1-1-any +installed = cfitsio-1:4.6.3-1.1-x86_64_v3 +installed = chromium-145.0.7632.109-1.1-x86_64_v3 +installed = chwd-1.18.0-3-x86_64 +installed = cifs-utils-7.4-1.2-x86_64_v3 +installed = cinny-web-4.10.5-1-any +installed = cjson-1.7.19-1.1-x86_64_v3 +installed = clang-21.1.8-1.1-x86_64_v3 +installed = clang20-20.1.8-1.1-x86_64_v3 +installed = clazy-1.17-1.1-x86_64_v3 +installed = cli11-2.6.1-1-any +installed = clinfo-3.0.23.01.25-1.1-x86_64 +installed = clipboard-sync-0.2.0-1-x86_64 +installed = cliphist-1:0.7.0-2.1-x86_64_v3 +installed = cloudflared-2026.2.0-1.1-x86_64_v3 +installed = clucene-2.3.3.4-17.1-x86_64_v3 +installed = cmake-4.2.3-1.1-x86_64_v3 +installed = cmark-0.31.2-1.1-x86_64_v3 +installed = coeurl-0.3.1-7.1-x86_64_v3 +installed = compiler-rt-21.1.8-1-x86_64 +installed = compiler-rt20-20.1.8-1.2-x86_64_v3 +installed = composefs-1.0.8-1.1-x86_64_v3 +installed = containerd-2.2.1-1.1-x86_64_v3 +installed = convertlit-1.8-13.1-x86_64_v3 +installed = coppwr-1.7.1-1-x86_64 +installed = copyparty-1.20.7-1-any +installed = coreutils-9.10-1.1-x86_64_v3 +installed = cpio-2.15-3.1-x86_64_v3 +installed = cppdap-1.58.0-2.1-x86_64 +installed = cpupower-6.19-2-x86_64 +installed = cracklib-2.10.3-1.1-x86_64_v3 +installed = croc-1:10.3.1-1-x86_64 +installed = cronie-1.7.2-2.1-x86_64_v3 +installed = cryptsetup-2.8.4-1.1-x86_64_v3 +installed = cuda-13.1.1-1-x86_64 +installed = curl-8.18.0-3.1-x86_64_v3 +installed = cython-3.2.4-3.1-x86_64_v3 +installed = darkly-0.5.32-1-x86_64 +installed = dart-sass-1.97.3-1.1-x86_64_v3 +installed = dav1d-1.5.3-1.1-x86_64_v3 +installed = davinci-resolve-20.3.2-1-x86_64 +installed = db5.3-5.3.28-7.1-x86_64_v3 +installed = dbus-1.16.2-1.1-x86_64_v3 +installed = dbus-broker-37-3.1-x86_64_v3 +installed = dbus-broker-units-37-3.1-x86_64_v3 +installed = dbus-glib-0.114-1.1-x86_64_v3 +installed = dbus-units-37-3.1-x86_64_v3 +installed = dconf-0.49.0-1.1-x86_64_v3 +installed = ddcci-driver-linux-dkms-0.4.5-1-x86_64 +installed = ddcutil-2.2.5-2.1-x86_64_v3 +installed = debtap-3.6.3-1-any +installed = debugedit-5.2-1.1-x86_64_v3 +installed = debuginfod-0.194-1-x86_64 +installed = default-cursors-3-1-any +installed = deno-2.6.10-1.1-x86_64_v3 +installed = desktop-file-utils-0.28-1.1-x86_64 +installed = device-mapper-2.03.38-1.1-x86_64_v3 +installed = diffutils-3.12-2.1-x86_64_v3 +installed = discord-1:0.0.125-1-x86_64 +installed = discord-canary-0.0.873-1-x86_64 +installed = dkms-3.3.0-2-any +installed = dmidecode-3.7-1-x86_64 +installed = dnsmasq-2.92-1.1-x86_64_v3 +installed = dnssec-anchors-20250524-1-any +installed = docbook-xml-4.5-11-any +installed = docbook-xsl-1.79.2-9-any +installed = docker-1:29.2.1-1.1-x86_64_v3 +installed = docker-buildx-0.31.1-1.1-x86_64_v3 +installed = doctest-2.4.12-1-any +installed = dolphin-25.12.2-1.1-x86_64_v3 +installed = dos2unix-7.5.4-1.1-x86_64_v3 +installed = dosbox-0.74.3-3.1-x86_64 +installed = dosfstools-4.2-5.1-x86_64 +installed = dotnet-host-10.0.3.sdk103-1-x86_64 +installed = dotnet-runtime-10.0.3.sdk103-1-x86_64 +installed = dotnet-sdk-10.0.3.sdk103-1-x86_64 +installed = dotnet-targeting-pack-10.0.3.sdk103-1-x86_64 +installed = dotool-1.6-1-x86_64 +installed = double-conversion-3.4.0-1.1-x86_64_v3 +installed = downgrade-11.8.0-1-any +installed = doxygen-1.16.1-2.1-x86_64_v3 +installed = dpkg-1.23.5-2.1-x86_64_v3 +installed = drm_info-git-2.9.0.r6.ga7b4cd50-1-x86_64 +installed = dtc-1.7.2-5.1-x86_64_v3 +installed = dtools-2.112.0-1-x86_64 +installed = dub-1.41.0-1.1-x86_64_v3 +installed = duktape-2.7.0-7.1-x86_64 +installed = dunst-1.13.1-1.1-x86_64_v3 +installed = dupeguru-4.3.1-3-any +installed = e2fsprogs-1.47.3-2.1-x86_64_v3 +installed = easyeffects-8.1.2-1.1-x86_64_v3 +installed = ebook-tools-0.2.2-9.1-x86_64_v3 +installed = eclipse-java-bin-2:4.38-1-x86_64 +installed = editline-1.17.1-4.1-x86_64_v3 +installed = editorconfig-core-c-0.12.10-1.1-x86_64_v3 +installed = edk2-aarch64-202508-1-any +installed = edk2-arm-202508-1-any +installed = edk2-ovmf-202508-1-any +installed = efibootmgr-18-3.1-x86_64 +installed = efivar-39-1.1-x86_64 +installed = egl-gbm-1.1.3-1.1-x86_64_v3 +installed = egl-wayland-4:1.1.21-1.1-x86_64_v3 +installed = egl-wayland2-1.0.0.rc.r57.g1893c37-1.1-x86_64_v3 +installed = egl-x11-1.0.4-1.1-x86_64_v3 +installed = eglexternalplatform-1.2.1-1-any +installed = electron-1:39-1-any +installed = electron31-31.7.7-4-x86_64 +installed = electron36-36.9.3-1.1-x86_64_v3 +installed = electron37-37.5.1-1-x86_64 +installed = electron39-39.5.2-1-x86_64 +installed = electron40-bin-40.5.0-1-x86_64 +installed = element-desktop-1.12.9-1-x86_64 +installed = element-web-1.12.9-1-x86_64 +installed = elfutils-0.194-1-x86_64 +installed = ell-0.82-1.1-x86_64_v3 +installed = enchant-2.8.14-1.1-x86_64_v3 +installed = entr-5.7-1.1-x86_64_v3 +installed = etcher-bin-2.1.4-1-x86_64 +installed = ethtool-1:6.19-1.1-x86_64_v3 +installed = evolution-data-server-3.58.3-1-x86_64 +installed = eww-0.6.0-1-x86_64 +installed = execstack-20130503-10-x86_64 +installed = exiv2-0.28.7-1.2-x86_64_v3 +installed = exo-4.20.0-2.1-x86_64 +installed = expac-10-12.2-x86_64_v3 +installed = expat-2.7.4-1.1-x86_64_v3 +installed = extra-cmake-modules-6.23.0-1-any +installed = f2fs-tools-1.16.0-3.1-x86_64 +installed = faad2-2.11.2-1.2-x86_64_v3 +installed = fabric-cli-git-0.0.2-1-x86_64 +installed = fail2ban-1.1.0-8-any +installed = fakeroot-1.37.2-1.1-x86_64_v3 +installed = farstream-0.2.9-4.1-x86_64_v3 +installed = fastfetch-2.59.0-1.1-x86_64_v3 +installed = faudio-25.12-1-x86_64 +installed = fcft-3.3.3-1.1-x86_64_v3 +installed = fchat-horizon-bin-1.35.7-1-x86_64 +installed = fd-10.3.0-2.1-x86_64_v3 +installed = ffcall-2.5-1.1-x86_64_v3 +installed = ffmpeg-2:8.0.1-7-x86_64 +installed = ffmpeg4.4-4.4.6-4.1-x86_64_v3 +installed = ffmpegthumbnailer-2.3.0-1.1-x86_64_v3 +installed = fftw-3.3.10-8.1-x86_64_v3 +installed = file-5.46-5.1-x86_64_v3 +installed = filesystem-2025.10.12-1-any +installed = findutils-4.10.0-3.1-x86_64_v3 +installed = firefox-nightly-bin-149.0a1.20260206.213744-1-x86_64 +installed = fish-4.5.0-2-x86_64 +installed = flac-1.5.0-1.2-x86_64_v3 +installed = flatpak-1:1.16.3-1.1-x86_64_v3 +installed = flatpak-kcm-6.6.0-1.1-x86_64_v3 +installed = flex-2.6.4-5.1-x86_64 +installed = flow-browser-bin-0.8.4-1-x86_64 +installed = fluent-icon-theme-git-2025.08.21.r6.g8a99a6d-1-any +installed = fluidsynth-2.5.2-1.1-x86_64_v3 +installed = fmt-12.1.0-1.1-x86_64_v3 +installed = fontconfig-2:2.17.1-1.1-x86_64_v3 +installed = fontforge-20251009-5.1-x86_64_v3 +installed = foot-1.25.0-1-x86_64 +installed = foot-terminfo-1.25.0-1-x86_64 +installed = forkstat-0.03.02-1-x86_64 +installed = fotokilof-5.2.3-1-any +installed = fpp-0.9.5-1-any +installed = frameworkintegration-6.23.0-1.1-x86_64_v3 +installed = frameworkintegration5-5.116.0-2.1-x86_64_v3 +installed = franz-bin-5.11.0-1-x86_64 +installed = freeglut-3.8.0-1.1-x86_64_v3 +installed = freeimage-3.18.0-23-x86_64 +installed = freerdp-2:3.22.0-2.1-x86_64_v3 +installed = freetube-git-0.23.13.beta.r9823.92dd43a-1-x86_64 +installed = freetype2-2.14.1-2.1-x86_64_v3 +installed = fribidi-1.0.16-2.1-x86_64_v3 +installed = fuse-common-3.18.1-1.1-x86_64_v3 +installed = fuse2-2.9.9-5-x86_64 +installed = fuse3-3.18.1-1.1-x86_64_v3 +installed = fuzzel-1.14.0-2.1-x86_64_v3 +installed = fzf-0.68.0-1.1-x86_64_v3 +installed = gamemode-1.8.2-1.1-x86_64 +installed = gamescope-git-3.16.20.r2.g2392f6e0-1-x86_64 +installed = gammastep-2.0.11-2.1-x86_64_v3 +installed = gawk-5.3.2-1.1-x86_64_v3 +installed = gc-8.2.12-1.1-x86_64_v3 +installed = gcc-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = gcc-libs-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = gcr-4-4.4.0.1-1.1-x86_64_v3 +installed = gd-2.3.3-9-x86_64 +installed = gdbm-1.26-2.1-x86_64_v3 +installed = gdk-pixbuf2-2.44.4-1.1-x86_64_v3 +installed = gegl-0.4.66-2.1-x86_64_v3 +installed = geocode-glib-2-3.26.4-5.3-x86_64_v3 +installed = geocode-glib-common-3.26.4-5.3-x86_64_v3 +installed = gettext-1.0-2.1-x86_64_v3 +installed = gfxstream-0.1.2-2.1-x86_64_v3 +installed = ghostscript-10.06.0-1.1-x86_64_v3 +installed = ghostty-1.2.3-3-x86_64 +installed = ghostty-shell-integration-1.2.3-3-x86_64 +installed = ghostty-terminfo-1.2.3-3-x86_64 +installed = giflib-5.2.2-2.1-x86_64_v3 +installed = gimp-3.0.8-2-x86_64 +installed = girara-2026.02.04-2.1-x86_64_v3 +installed = git-2.53.0-1.1-x86_64_v3 +installed = git-credential-oauth-git-0.17.2.r1.g031d9b7-1-any +installed = git-lfs-3.7.1-1.1-x86_64_v3 +installed = github-cli-2.87.2-1.1-x86_64_v3 +installed = gituserchrome-1.2-1-x86_64 +installed = gjs-2:1.86.0-1.1-x86_64_v3 +installed = glaze-7.0.2-1-any +installed = glew1.10-1.10.0-4-x86_64 +installed = glfw-1:3.4-1.1-x86_64_v3 +installed = glib-networking-1:2.80.1-1.1-x86_64_v3 +installed = glib2-2.86.4-1.3-x86_64_v3 +installed = glib2-devel-2.86.4-1.3-x86_64_v3 +installed = glib2-docs-2.86.4-1.3-x86_64_v3 +installed = glibc-2.43+r5+g856c426a7534-3-x86_64 +installed = glibmm-2.66.8-1.1-x86_64_v3 +installed = glibmm-2.68-2.86.0-1.1-x86_64_v3 +installed = glm-1.0.3-1.1-x86_64_v3 +installed = glmark2-2023.01-2.1-x86_64 +installed = glslang-1:1.4.341.0-1.1-x86_64_v3 +installed = glu-9.0.3-3.1-x86_64_v3 +installed = glusterfs-1:11.2-2.1-x86_64_v3 +installed = glycin-2.0.8-1.1-x86_64_v3 +installed = gmp-6.3.0-3.1-x86_64_v3 +installed = gnome-bluetooth-3.0-47.1-2.2-x86_64_v3 +installed = gnome-common-3.18.0-5-any +installed = gnome-desktop-1:44.5-1.1-x86_64_v3 +installed = gnome-desktop-4-1:44.5-1.1-x86_64_v3 +installed = gnome-desktop-common-1:44.5-1.1-x86_64_v3 +installed = gnome-disk-utility-46.1-2.1-x86_64_v3 +installed = gnu-free-fonts-20120503-9-any +installed = gnulib-l10n-20241231-1-any +installed = gnupg-2.4.9-1.1-x86_64_v3 +installed = gnuplot-6.0.4-1.1-x86_64_v3 +installed = gnutls-3.8.12-2-x86_64 +installed = go-2:1.26.0-3-x86_64_v3 +installed = go-chroma-2.15.0-1-x86_64 +installed = go-tools-4:0.42.0-2.1-x86_64_v3 +installed = gobject-introspection-1.86.0-2.1-x86_64_v3 +installed = gobject-introspection-runtime-1.86.0-2.1-x86_64_v3 +installed = gocryptfs-2.6.1-1.1-x86_64_v3 +installed = google-breakpad-v2024.02.16-2-x86_64 +installed = goverlay-git-1.6.1.r75.g1853d83-1-x86_64 +installed = gparted-1.8.0-1.1-x86_64_v3 +installed = gperf-3.3-2.1-x86_64_v3 +installed = gperftools-2.17.2-1.1-x86_64_v3 +installed = gpgme-2.0.1-1.1-x86_64_v3 +installed = gpgmepp-2.0.0-2.1-x86_64_v3 +installed = gpm-1.20.7.r38.ge82d1a6-6.1-x86_64 +installed = gpsd-3.27.5-1.1-x86_64_v3 +installed = gptfdisk-1.0.10-2.1-x86_64_v3 +installed = gpu-screen-recorder-5.12.4-1.1-x86_64_v3 +installed = grantleetheme-25.12.2-1.1-x86_64_v3 +installed = graphene-1.10.8-2.1-x86_64 +installed = graphicsmagick-1.3.46-1.1-x86_64_v3 +installed = graphite-1:1.3.14-6-x86_64 +installed = graphviz-14.1.2-1-x86_64 +installed = greetd-0.10.3-1.1-x86_64 +installed = greetd-agreety-0.10.3-1.1-x86_64 +installed = grep-3.12-2.1-x86_64_v3 +installed = grim-1.5.0-2.1-x86_64_v3 +installed = grimblast-git-r154.541628c-1-any +installed = groff-1.23.0-8.1-x86_64_v3 +installed = grub-2:2.14-1.1-x86_64_v3 +installed = grub-btrfs-4.14-1-any +installed = gsettings-desktop-schemas-49.1-1-any +installed = gsettings-system-schemas-49.1-1-any +installed = gsfonts-20200910-6-any +installed = gsl-2.8-1-x86_64 +installed = gsm-1.0.23-1.1-x86_64_v3 +installed = gsound-1.0.3-3.1-x86_64 +installed = gspell-1.14.2-1.1-x86_64_v3 +installed = gssdp-1.6.4-1.1-x86_64_v3 +installed = gst-libav-1.28.0-2.1-x86_64_v3 +installed = gst-plugin-gtk-1.28.0-2.1-x86_64_v3 +installed = gst-plugin-pipewire-1:1.4.10-2.1-x86_64_v3 +installed = gst-plugin-va-1.28.0-2.1-x86_64_v3 +installed = gst-plugins-bad-libs-1.28.0-2.1-x86_64_v3 +installed = gst-plugins-base-1.28.0-2.1-x86_64_v3 +installed = gst-plugins-base-libs-1.28.0-2.1-x86_64_v3 +installed = gst-plugins-good-1.28.0-2.1-x86_64_v3 +installed = gst-plugins-ugly-1.28.0-2.1-x86_64_v3 +installed = gstreamer-1.28.0-2.1-x86_64_v3 +installed = gtest-1.17.0-2.1-x86_64_v3 +installed = gtk-doc-1.35.1-1-any +installed = gtk-layer-shell-0.10.0-1.1-x86_64_v3 +installed = gtk-sharp-2-2.12.45-8-x86_64 +installed = gtk-update-icon-cache-1:4.20.3-1.1-x86_64_v3 +installed = gtk2-2.24.33-5-x86_64 +installed = gtk3-1:3.24.51-1.1-x86_64_v3 +installed = gtk4-1:4.20.3-1.1-x86_64_v3 +installed = gtk4-layer-shell-1.3.0-1.1-x86_64_v3 +installed = gtkmm-4.0-4.20.0-1.2-x86_64_v3 +installed = gtkmm3-3.24.10-1.2-x86_64_v3 +installed = gtksourceview3-1:3.24.11+r30+gd880929f-1.1-x86_64_v3 +installed = gtksourceview4-4.8.4-2.1-x86_64_v3 +installed = gtksourceview5-5.18.0-1.1-x86_64_v3 +installed = gtkspell-2.0.16-10-x86_64 +installed = gts-0.7.6.121130-5.1-x86_64_v3 +installed = guile-3.0.11-1.1-x86_64_v3 +installed = gulp-5.0.1-1-any +installed = gumbo-parser-0.13.2-1.1-x86_64_v3 +installed = gupnp-1:1.6.9-1.1-x86_64_v3 +installed = gupnp-igd-1.6.0-2.1-x86_64_v3 +installed = guvcview-2.2.1-2.1-x86_64_v3 +installed = guvcview-common-2.2.1-2.1-x86_64_v3 +installed = gvfs-1.58.1-1-x86_64 +installed = gwenview-25.12.2-1.1-x86_64_v3 +installed = gzip-1.14-2-x86_64 +installed = half-2.2.1-1-any +installed = handlr-regex-0.13.0-1.1-x86_64_v3 +installed = harfbuzz-12.3.2-1.1-x86_64_v3 +installed = harfbuzz-icu-12.3.2-1.1-x86_64_v3 +installed = helix-25.07.1-1.1-x86_64_v3 +installed = helvum-0.5.1-1-x86_64 +installed = hicolor-icon-theme-0.18-1-any +installed = hidapi-0.15.0-1.1-x86_64_v3 +installed = highway-1.3.0-2.1-x86_64_v3 +installed = hiredis-1.3.0-1.1-x86_64_v3 +installed = htop-3.4.1-1.1-x86_64_v3 +installed = hunspell-1.7.2-3.1-x86_64_v3 +installed = hwdata-0.404-1-any +installed = hwloc-2.13.0-1.1-x86_64_v3 +installed = hyperv-6.19-2-x86_64 +installed = hyphen-2.8.8-6.2-x86_64_v3 +installed = hyprcursor-0.1.13-3.1-x86_64_v3 +installed = hyprgraphics-0.5.0-1.1-x86_64_v3 +installed = hypridle-0.1.7-6.1-x86_64_v3 +installed = hyprland-0.53.3-2.1-x86_64_v3 +installed = hyprland-guiutils-0.2.1-2.1-x86_64_v3 +installed = hyprland-protocols-git-0.7.0.r1.g3f3860b-1-x86_64 +installed = hyprland-qt-support-0.1.0-10.1-x86_64_v3 +installed = hyprlang-0.6.8-1.1-x86_64_v3 +installed = hyprlauncher-0.1.5-2.1-x86_64_v3 +installed = hyprpicker-0.4.6-2.1-x86_64_v3 +installed = hyprpolkitagent-0.1.3-4.1-x86_64_v3 +installed = hyprpwcenter-0.1.2-1.1-x86_64_v3 +installed = hyprqt6engine-0.1.0-2-x86_64 +installed = hyprsunset-0.3.3-4.1-x86_64_v3 +installed = hyprtoolkit-0.5.3-1.1-x86_64_v3 +installed = hyprutils-0.11.0-1.1-x86_64_v3 +installed = hyprwayland-scanner-0.4.5-1.1-x86_64_v3 +installed = hyprwire-0.3.0-1.1-x86_64_v3 +installed = i2c-tools-4.4-4.1-x86_64_v3 +installed = iana-etc-20260203-1-any +installed = icoextract-0.2.0-2-any +installed = icu-78.2-2.1-x86_64_v3 +installed = ijs-0.35-6.1-x86_64 +installed = iloader-bin-2.0.6-1-x86_64 +installed = imagemagick-7.1.2.15-1.1-x86_64_v3 +installed = imath-3.2.2-3.1-x86_64_v3 +installed = imlib2-1.12.6-1.1-x86_64_v3 +installed = imv-5.0.1-1.1-x86_64_v3 +installed = inetutils-2.7-2.1-x86_64_v3 +installed = iniparser-4.2.6-2.1-x86_64_v3 +installed = inkscape-1.4.3-2.1-x86_64_v3 +installed = inotify-tools-4.25.9.0-1.1-x86_64_v3 +installed = intel-speed-select-6.19-2-x86_64 +installed = intel-ucode-20260210-1-any +installed = intltool-0.51.0-6-any +installed = inxi-3.3.40.1-1-any +installed = iotop-0.6-13-any +installed = iproute2-6.19.0-2.1-x86_64_v3 +installed = iptables-1:1.8.11-2.1-x86_64_v3 +installed = iputils-20250605-1.1-x86_64_v3 +installed = irqbalance-1.9.5-3-x86_64 +installed = iso-codes-4.20.1-1-any +installed = itstool-1:2.0.7-3-any +installed = iwd-3.11-2.1-x86_64_v3 +installed = jack_delay-0.4.2-3.1-x86_64 +installed = jansson-2.15.0-1.1-x86_64_v3 +installed = jasper-4.2.8-1.1-x86_64_v3 +installed = java-commons-lang-3.20.0-1-any +installed = java-environment-common-3-6-any +installed = java-runtime-common-3-6-any +installed = jbig2dec-0.20-1.1-x86_64 +installed = jbigkit-2.1-8.1-x86_64 +installed = jdk-openjdk-25.0.2.u10-2-x86_64_v3 +installed = jdk17-openjdk-17.0.18.u8-2-x86_64_v3 +installed = jdk21-openjdk-21.0.10.u7-2-x86_64_v3 +installed = jemalloc-1:5.3.0-5.1-x86_64 +installed = jq-1.8.1-1.1-x86_64_v3 +installed = js140-140.7.1-1.1-x86_64_v3 +installed = json-c-0.18-2.1-x86_64_v3 +installed = json-glib-1.10.8-1.1-x86_64_v3 +installed = jsoncpp-1.9.6-3.3-x86_64_v3 +installed = just-1.46.0-1.1-x86_64_v3 +installed = jxrlib-0.2.4-2.1-x86_64 +installed = kaccounts-integration-25.12.2-1.1-x86_64_v3 +installed = kactivitymanagerd-6.6.0-1.1-x86_64_v3 +installed = karchive-6.23.0-1.1-x86_64_v3 +installed = karchive5-5.116.0-2.1-x86_64_v3 +installed = kate-25.12.2-1.1-x86_64_v3 +installed = kauth-6.23.0-1.1-x86_64_v3 +installed = kauth5-5.116.0-2.1-x86_64_v3 +installed = kbd-2.9.0-1.1-x86_64_v3 +installed = kbookmarks-6.23.0-1.1-x86_64_v3 +installed = kbookmarks5-5.116.0-2.1-x86_64_v3 +installed = kcalendarcore-6.23.0-1.1-x86_64_v3 +installed = kcalutils-25.12.2-1.1-x86_64_v3 +installed = kcmutils-6.23.0-1.1-x86_64_v3 +installed = kcmutils5-5.116.0-2.1-x86_64_v3 +installed = kcodecs-6.23.0-1.2-x86_64_v3 +installed = kcodecs5-5.116.0-2.4-x86_64_v3 +installed = kcolorpicker-0.3.1-5-x86_64 +installed = kcolorscheme-6.23.0-1.1-x86_64_v3 +installed = kcompletion-6.23.0-1.1-x86_64_v3 +installed = kcompletion5-5.116.0-2.1-x86_64_v3 +installed = kconfig-6.23.0-1.1-x86_64_v3 +installed = kconfig5-5.116.0-2.1-x86_64_v3 +installed = kconfigwidgets-6.23.0-1.1-x86_64_v3 +installed = kconfigwidgets5-5.116.0-3.1-x86_64_v3 +installed = kcontacts-1:6.23.0-1.1-x86_64_v3 +installed = kcoreaddons-6.23.0-1.1-x86_64_v3 +installed = kcoreaddons5-5.116.0-2.1-x86_64_v3 +installed = kcpuid-6.19-2-x86_64 +installed = kcrash-6.23.0-1.1-x86_64_v3 +installed = kcrash5-5.116.0-2.1-x86_64_v3 +installed = kdav-1:6.23.0-1.1-x86_64_v3 +installed = kdbusaddons-6.23.0-1.1-x86_64_v3 +installed = kdbusaddons5-5.116.0-2.1-x86_64_v3 +installed = kde-cli-tools-6.6.0-1.1-x86_64_v3 +installed = kde-gtk-config-6.6.0-1.1-x86_64_v3 +installed = kdeclarative-6.23.0-1.1-x86_64_v3 +installed = kdeclarative5-5.116.0-2.1-x86_64_v3 +installed = kdecoration-6.6.0-1.1-x86_64_v3 +installed = kded-6.23.0-1.1-x86_64_v3 +installed = kded5-5.116.0-2.1-x86_64_v3 +installed = kdepim-runtime-25.12.2-1.1-x86_64_v3 +installed = kdeplasma-addons-6.6.0-1.1-x86_64_v3 +installed = kdesu-6.23.0-1.1-x86_64_v3 +installed = kdnssd-6.23.0-1.1-x86_64_v3 +installed = kdsingleapplication-1.2.0-1.1-x86_64_v3 +installed = kdsoap-qt6-2.2.0-1-x86_64 +installed = kdsoap-ws-discovery-client-0.4.0-2.1-x86_64_v3 +installed = keepassxc-2.7.11-1-x86_64 +installed = keyutils-1.6.3-3.1-x86_64 +installed = kfilemetadata-6.23.0-1.1-x86_64_v3 +installed = kgamma-6.6.0-1.1-x86_64_v3 +installed = kglobalaccel-6.23.0-1.1-x86_64_v3 +installed = kglobalaccel5-5.116.0-2.1-x86_64_v3 +installed = kglobalacceld-6.6.0-1.1-x86_64_v3 +installed = kguiaddons-6.23.0-1.1-x86_64_v3 +installed = kguiaddons5-5.116.0-2.1-x86_64_v3 +installed = kholidays-1:6.23.0-1.1-x86_64_v3 +installed = ki18n-6.23.0-1.1-x86_64_v3 +installed = ki18n5-5.116.0-2.1-x86_64_v3 +installed = kiconthemes-6.23.0-1.1-x86_64_v3 +installed = kiconthemes5-5.116.0-2.1-x86_64_v3 +installed = kidentitymanagement-25.12.2-1.1-x86_64_v3 +installed = kidletime-6.23.0-1.1-x86_64_v3 +installed = kimageannotator-0.7.2-1-x86_64 +installed = kimap-25.12.2-1.1-x86_64_v3 +installed = kinfocenter-6.6.0-1.1-x86_64_v3 +installed = kio-6.23.0-1.1-x86_64_v3 +installed = kio-admin-25.12.2-1.1-x86_64_v3 +installed = kio-extras-25.12.2-1.1-x86_64_v3 +installed = kio-fuse-5.1.1-1.1-x86_64_v3 +installed = kio5-5.116.0-5.1-x86_64_v3 +installed = kirigami-6.23.0-1.1-x86_64_v3 +installed = kirigami-addons-1.11.0-1.1-x86_64_v3 +installed = kirigami2-5.116.0-2.1-x86_64_v3 +installed = kitemmodels-6.23.0-1.1-x86_64_v3 +installed = kitemviews-6.23.0-1.1-x86_64_v3 +installed = kitemviews5-5.116.0-2.1-x86_64_v3 +installed = kitty-0.45.0-4.1-x86_64_v3 +installed = kitty-shell-integration-0.45.0-4.1-x86_64_v3 +installed = kitty-terminfo-0.45.0-4.1-x86_64_v3 +installed = kjobwidgets-6.23.0-1.1-x86_64_v3 +installed = kjobwidgets5-5.116.0-2.1-x86_64_v3 +installed = kldap-25.12.2-1.1-x86_64_v3 +installed = kmailtransport-25.12.2-1.1-x86_64_v3 +installed = kmbox-25.12.2-1.1-x86_64_v3 +installed = kmenuedit-6.6.0-1.1-x86_64_v3 +installed = kmime-25.12.2-1.1-x86_64_v3 +installed = kmod-34.2-1-x86_64 +installed = knewstuff-6.23.0-1.1-x86_64_v3 +installed = knighttime-6.6.0-1.1-x86_64_v3 +installed = knotifications-6.23.0-1.1-x86_64_v3 +installed = knotifications5-5.116.0-3.1-x86_64_v3 +installed = knotifyconfig-6.23.0-1.1-x86_64_v3 +installed = kpackage-6.23.0-1.1-x86_64_v3 +installed = kpackage5-5.116.0-3.1-x86_64_v3 +installed = kparts-6.23.0-1.1-x86_64_v3 +installed = kpimtextedit-25.12.2-1.1-x86_64_v3 +installed = kpipewire-6.6.0-1.1-x86_64_v3 +installed = kpty-6.23.0-1.1-x86_64_v3 +installed = kquickcharts-6.23.0-1.1-x86_64_v3 +installed = kquickimageeditor-0.6.0-2.1-x86_64_v3 +installed = krb5-1.21.3-2.1-x86_64_v3 +installed = krdp-6.6.0-1.1-x86_64_v3 +installed = krunner-6.23.0-1.1-x86_64_v3 +installed = kscreenlocker-6.6.0-1.1-x86_64_v3 +installed = kservice-6.23.0-1.1-x86_64_v3 +installed = kservice5-5.116.0-3.1-x86_64_v3 +installed = ksmtp-25.12.2-1.1-x86_64_v3 +installed = kstatusnotifieritem-6.23.0-1.1-x86_64_v3 +installed = ksvg-6.23.0-1.1-x86_64_v3 +installed = ksystemstats-6.6.0-1.1-x86_64_v3 +installed = ktextaddons-1.9.1-1.1-x86_64_v3 +installed = ktexteditor-6.23.0-1.1-x86_64_v3 +installed = ktexttemplate-6.23.0-1.1-x86_64_v3 +installed = ktextwidgets-6.23.0-1.1-x86_64_v3 +installed = ktextwidgets5-5.116.0-2.1-x86_64_v3 +installed = kunitconversion-6.23.0-1.1-x86_64_v3 +installed = kuserfeedback-6.23.0-1.1-x86_64_v3 +installed = kvantum-1.1.6-1.1-x86_64_v3 +installed = kwallet-6.23.0-1.1-x86_64_v3 +installed = kwallet-pam-6.6.0-1.1-x86_64_v3 +installed = kwallet5-5.116.0-5.1-x86_64_v3 +installed = kwalletmanager-25.12.2-1.1-x86_64_v3 +installed = kwayland-6.6.0-1.1-x86_64_v3 +installed = kwidgetsaddons-6.23.0-1.1-x86_64_v3 +installed = kwidgetsaddons5-5.116.0-2.1-x86_64_v3 +installed = kwin-6.6.0-1.1-x86_64_v3 +installed = kwindowsystem-6.23.0-1.1-x86_64_v3 +installed = kwindowsystem5-5.116.0-2.1-x86_64_v3 +installed = kwrited-6.6.0-1.1-x86_64_v3 +installed = kxmlgui-6.23.0-1.1-x86_64_v3 +installed = kxmlgui5-5.116.0-2.1-x86_64_v3 +installed = l-smash-2.14.5-4.1-x86_64 +installed = lact-git-r1061.d39b963c-1-x86_64 +installed = lame-3.101.r6531-1.1-x86_64_v3 +installed = lapack-3.12.1-2.1-x86_64_v3 +installed = layer-shell-qt-6.6.0-1.1-x86_64_v3 +installed = lazygit-0.59.0-1.1-x86_64_v3 +installed = lcms2-2.18-1.1-x86_64_v3 +installed = ldb-2:4.23.5-1.1-x86_64_v3 +installed = ldc-3:1.41.0-2-x86_64 +installed = leancrypto-1.6.0-1.1-x86_64_v3 +installed = lensfun-1:0.3.4-6.1-x86_64_v3 +installed = leptonica-1.87.0-1.1-x86_64_v3 +installed = less-1:692-1.1-x86_64_v3 +installed = lib2geom-1.4-2-x86_64 +installed = lib32-aalib-1.4rc5-5-x86_64 +installed = lib32-acl-2.3.2-1-x86_64 +installed = lib32-alsa-lib-1.2.15.3-1-x86_64 +installed = lib32-alsa-plugins-1.2.12-1-x86_64 +installed = lib32-at-spi2-core-2.58.3-1-x86_64 +installed = lib32-attr-2.5.2-1-x86_64 +installed = lib32-audit-4.1.2-1-x86_64 +installed = lib32-brotli-1.1.0-1-x86_64 +installed = lib32-bzip2-1.0.8-4-x86_64 +installed = lib32-cairo-1.18.4-1-x86_64 +installed = lib32-cdparanoia-10.2-5-x86_64 +installed = lib32-colord-1.4.8-1-x86_64 +installed = lib32-curl-8.18.0-4-x86_64 +installed = lib32-dbus-1.16.2-1-x86_64 +installed = lib32-dbus-glib-0.114-1-x86_64 +installed = lib32-duktape-2.7.0-7-x86_64 +installed = lib32-e2fsprogs-1.47.3-2-x86_64 +installed = lib32-expat-2.7.4-1-x86_64 +installed = lib32-flac-1.5.0-1-x86_64 +installed = lib32-fontconfig-2:2.17.1-1-x86_64 +installed = lib32-freeglut-3.8.0-1.1-x86_64 +installed = lib32-freetype2-2.14.1-1-x86_64 +installed = lib32-fribidi-1.0.16-2-x86_64 +installed = lib32-gcc-libs-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = lib32-gdk-pixbuf2-2.44.4-1-x86_64 +installed = lib32-gettext-0.26-1-x86_64 +installed = lib32-giflib-5.2.2-1-x86_64 +installed = lib32-glew1.10-1.10.0-6-x86_64 +installed = lib32-glib-networking-1:2.80.1-1-x86_64 +installed = lib32-glib2-2.86.4-1-x86_64 +installed = lib32-glibc-2.43+r5+g856c426a7534-3-x86_64 +installed = lib32-glu-9.0.3-2-x86_64 +installed = lib32-gmp-6.3.0-2-x86_64 +installed = lib32-gnutls-3.8.12-1-x86_64 +installed = lib32-gpm-1.20.7.r38.ge82d1a6-2-x86_64 +installed = lib32-gst-plugins-base-1.26.10-1-x86_64 +installed = lib32-gst-plugins-base-libs-1.26.10-1-x86_64 +installed = lib32-gst-plugins-good-1.26.10-1-x86_64 +installed = lib32-gstreamer-1.26.10-1-x86_64 +installed = lib32-gtk2-2.24.33-5-x86_64 +installed = lib32-gtk3-1:3.24.51-1-x86_64 +installed = lib32-harfbuzz-12.3.2-1-x86_64 +installed = lib32-icu-78.2-1-x86_64 +installed = lib32-imlib2-1.12.6-1-x86_64 +installed = lib32-json-c-0.18-2-x86_64 +installed = lib32-keyutils-1.6.3-2-x86_64 +installed = lib32-krb5-1.21.3-1-x86_64 +installed = lib32-lcms2-2.17-1-x86_64 +installed = lib32-libappindicator-gtk2-12.10.0.r298-5-x86_64 +installed = lib32-libasyncns-1:0.8+r3+g68cd5af-3-x86_64 +installed = lib32-libavc1394-0.5.4-5-x86_64 +installed = lib32-libcaca-0.99.beta20-2-x86_64 +installed = lib32-libcanberra-1:0.30+r2+gc0620e4-4-x86_64 +installed = lib32-libcap-2.77-1-x86_64 +installed = lib32-libcups-2.4.16-1-x86_64 +installed = lib32-libcurl-compat-8.18.0-4-x86_64 +installed = lib32-libcurl-gnutls-8.18.0-4-x86_64 +installed = lib32-libdatrie-0.2.13-3-x86_64 +installed = lib32-libdbusmenu-glib-18.10.20180917-1-x86_64 +installed = lib32-libdbusmenu-gtk2-16.04.0-7-x86_64 +installed = lib32-libdrm-2.4.131-1-x86_64 +installed = lib32-libdv-1.0.0-9-x86_64 +installed = lib32-libelf-0.194-1-x86_64 +installed = lib32-libepoxy-1.5.10-2-x86_64 +installed = lib32-libffi-3.5.2-1-x86_64 +installed = lib32-libgcrypt-1.12.1-1-x86_64 +installed = lib32-libgcrypt15-1.5.6-8-x86_64 +installed = lib32-libglvnd-1.7.0-1-x86_64 +installed = lib32-libgpg-error-1.59-1-x86_64 +installed = lib32-libgudev-238-3-x86_64 +installed = lib32-libice-1.1.1-2-x86_64 +installed = lib32-libidn11-1.33-3-x86_64 +installed = lib32-libidn2-2.3.8-1-x86_64 +installed = lib32-libiec61883-1.2.0-5-x86_64 +installed = lib32-libindicator-gtk2-12.10.1-11-x86_64 +installed = lib32-libjpeg-turbo-3.1.3-1-x86_64 +installed = lib32-libjpeg6-turbo-1.5.3-4-x86_64 +installed = lib32-libldap-2.6.12-1-x86_64 +installed = lib32-libltdl-2.6.0-4-x86_64 +installed = lib32-libmikmod-3.3.13-1-x86_64 +installed = lib32-libmodplug-0.8.9.0-5-x86_64 +installed = lib32-libnghttp2-1.68.0-1-x86_64 +installed = lib32-libnghttp3-1.15.0-1-x86_64 +installed = lib32-libngtcp2-1.20.0-1-x86_64 +installed = lib32-libnl-3.12.0-1-x86_64 +installed = lib32-libnm-1.54.3-1-x86_64 +installed = lib32-libnsl-2.0.1-1-x86_64 +installed = lib32-libogg-1.3.6-1-x86_64 +installed = lib32-libpcap-1.10.6-1-x86_64 +installed = lib32-libpciaccess-0.18.1-1-x86_64 +installed = lib32-libpipewire-1:1.4.10-1-x86_64 +installed = lib32-libpng-1.6.55-1-x86_64 +installed = lib32-libpng12-1.2.59-3-x86_64 +installed = lib32-libproxy-0.5.12-1-x86_64 +installed = lib32-libpsl-0.21.5-1-x86_64 +installed = lib32-libpulse-17.0+r98+gb096704c0-1-x86_64 +installed = lib32-libraw1394-2.1.2-5-x86_64 +installed = lib32-librsvg-2:2.61.4-1-x86_64 +installed = lib32-librtmp0-2.6-1-x86_64 +installed = lib32-libshout-1:2.4.6-4-x86_64 +installed = lib32-libsm-1.2.6-1-x86_64 +installed = lib32-libsndfile-1.2.2-3-x86_64 +installed = lib32-libsoup-2.74.3-4-x86_64 +installed = lib32-libsoup3-3.6.6-1-x86_64 +installed = lib32-libssh2-1.11.1-1-x86_64 +installed = lib32-libtasn1-4.21.0-1-x86_64 +installed = lib32-libthai-0.1.29-3-x86_64 +installed = lib32-libtheora-1.2.0-1-x86_64 +installed = lib32-libtiff-4.7.1-1-x86_64 +installed = lib32-libtiff4-3.9.7-6-x86_64 +installed = lib32-libtirpc-1.3.7-1-x86_64 +installed = lib32-libudev0-shim-2-1-x86_64 +installed = lib32-libunistring-1.3-1-x86_64 +installed = lib32-libunwind-1.8.1-1-x86_64 +installed = lib32-libusb-1.0.29-1-x86_64 +installed = lib32-libva-2.22.0-1-x86_64 +installed = lib32-libvdpau-1.5-3-x86_64 +installed = lib32-libvorbis-1.3.7-4-x86_64 +installed = lib32-libvpx-1.15.2-2-x86_64 +installed = lib32-libvpx1.3-1.3.0-4-x86_64 +installed = lib32-libwebp-1.6.0-1-x86_64 +installed = lib32-libx11-1.8.13-1-x86_64 +installed = lib32-libxau-1.0.12-1-x86_64 +installed = lib32-libxcb-1.17.0-1-x86_64 +installed = lib32-libxcomposite-0.4.7-1-x86_64 +installed = lib32-libxcrypt-4.5.2-1-x86_64 +installed = lib32-libxcrypt-compat-4.5.2-1-x86_64 +installed = lib32-libxcursor-1.2.3-1-x86_64 +installed = lib32-libxdamage-1.1.7-1-x86_64 +installed = lib32-libxdmcp-1.1.5-1-x86_64 +installed = lib32-libxext-1.3.7-1-x86_64 +installed = lib32-libxfixes-6.0.1-2-x86_64 +installed = lib32-libxft-2.3.8-2-x86_64 +installed = lib32-libxi-1.8.2-1-x86_64 +installed = lib32-libxinerama-1.1.6-1-x86_64 +installed = lib32-libxkbcommon-1.13.1-1-x86_64 +installed = lib32-libxml2-2.15.1-4-x86_64 +installed = lib32-libxmu-1.3.1-1-x86_64 +installed = lib32-libxrandr-1.5.5-1-x86_64 +installed = lib32-libxrender-0.9.11-2-x86_64 +installed = lib32-libxshmfence-1.3.3-1-x86_64 +installed = lib32-libxslt-1.1.45-1-x86_64 +installed = lib32-libxss-1.2.4-2-x86_64 +installed = lib32-libxt-1.3.1-1-x86_64 +installed = lib32-libxtst-1.2.5-2-x86_64 +installed = lib32-libxv-1.0.12-2-x86_64 +installed = lib32-libxxf86vm-1.1.5-2-x86_64 +installed = lib32-llvm-libs-1:21.1.8-1-x86_64 +installed = lib32-lm_sensors-1:3.6.2-2-x86_64 +installed = lib32-lzo-2.10-2-x86_64 +installed = lib32-mesa-git-26.1.0_devel.218303.f71a38e9ded-1-x86_64_v3 +installed = lib32-mpg123-1.33.4-1-x86_64 +installed = lib32-ncurses-6.6-1-x86_64 +installed = lib32-nettle-3.10.2-1-x86_64 +installed = lib32-nspr-4.38.2-1-x86_64 +installed = lib32-nss-3.120.1-1-x86_64 +installed = lib32-nvidia-utils-590.48.01-2-x86_64_v3 +installed = lib32-ocl-icd-2.3.3-1-x86_64 +installed = lib32-openal-1.25.1-1-x86_64 +installed = lib32-openssl-1:3.6.1-1-x86_64 +installed = lib32-openssl-1.0-1.0.2.u-4-x86_64 +installed = lib32-openssl-1.1-1.1.1.w-3-x86_64 +installed = lib32-opus-1.6.1-1-x86_64 +installed = lib32-orc-0.4.42-1-x86_64 +installed = lib32-p11-kit-0.26.2-1-x86_64 +installed = lib32-pam-1.7.1-1-x86_64 +installed = lib32-pango-1:1.57.0-2-x86_64 +installed = lib32-pcre2-10.47-1-x86_64 +installed = lib32-pipewire-1:1.4.10-1-x86_64 +installed = lib32-pixman-0.46.4-1-x86_64 +installed = lib32-popt-1.19-2-x86_64 +installed = lib32-rust-libs-1:1.93.1-1.1-x86_64_v3 +installed = lib32-sdl12-compat-1.2.68-2-x86_64 +installed = lib32-sdl2-compat-2.32.64-1-x86_64 +installed = lib32-sdl2_image-2.8.4-1-x86_64 +installed = lib32-sdl2_mixer-2.8.0-1-x86_64 +installed = lib32-sdl2_ttf-2.24.0-2-x86_64 +installed = lib32-sdl3-3.4.2-1-x86_64 +installed = lib32-sdl_image-1.2.12-9-x86_64 +installed = lib32-sdl_mixer-1.2.12-6-x86_64 +installed = lib32-sdl_ttf-2.0.11-9-x86_64 +installed = lib32-speex-1.2.1-2-x86_64 +installed = lib32-spirv-tools-1:1.4.341.0-1-x86_64 +installed = lib32-sqlite-3.51.2-1-x86_64 +installed = lib32-systemd-259.1-1-x86_64 +installed = lib32-taglib-2.1.1-1-x86_64 +installed = lib32-tdb-1.4.13-1-x86_64 +installed = lib32-twolame-0.4.0-3-x86_64 +installed = lib32-util-linux-2.41.3-1-x86_64 +installed = lib32-v4l-utils-1.32.0-1-x86_64 +installed = lib32-vulkan-icd-loader-1.4.341.0-1-x86_64 +installed = lib32-wavpack-5.9.0-1-x86_64 +installed = lib32-wayland-1.24.0-1-x86_64 +installed = lib32-xz-5.8.2-1-x86_64 +installed = lib32-zlib-ng-2.3.3-2-x86_64_v3 +installed = lib32-zlib-ng-compat-2.3.3-2-x86_64_v3 +installed = lib32-zstd-1.5.7-2-x86_64_v3 +installed = libabw-0.1.3-6.1-x86_64_v3 +installed = libaccounts-glib-1.27-3.1-x86_64_v3 +installed = libaccounts-qt-1.17-1.1-x86_64 +installed = libadwaita-1:1.8.4-1.1-x86_64_v3 +installed = libaemu-0.1.2-5.1-x86_64_v3 +installed = libaio-0.3.113-3.1-x86_64 +installed = libajantv2-1:17.5.0-1-x86_64 +installed = libakonadi-25.12.2-1.1-x86_64_v3 +installed = libappindicator-12.10.1-1-x86_64 +installed = libappindicator-gtk2-12.10.0.r298-8-x86_64 +installed = libarchive-3.8.5-1.1-x86_64_v3 +installed = libasan-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libass-0.17.4-1.1-x86_64_v3 +installed = libassuan-3.0.0-1.1-x86_64 +installed = libastal-4-git-r857.eb235f8-1-x86_64 +installed = libastal-4-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-apps-git-r857.eb235f8-1-x86_64 +installed = libastal-apps-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-auth-git-r857.eb235f8-1-x86_64 +installed = libastal-auth-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-battery-git-r857.eb235f8-1-x86_64 +installed = libastal-battery-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-bluetooth-git-r857.eb235f8-1-x86_64 +installed = libastal-bluetooth-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-cava-git-r857.eb235f8-1-x86_64 +installed = libastal-cava-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-git-r857.eb235f8-1-x86_64 +installed = libastal-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-gjs-git-r857.eb235f8-1-x86_64 +installed = libastal-greetd-git-r857.eb235f8-1-x86_64 +installed = libastal-greetd-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-hyprland-git-r857.eb235f8-1-x86_64 +installed = libastal-hyprland-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-io-git-r857.eb235f8-1-x86_64 +installed = libastal-io-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-meta-1-8-any +installed = libastal-mpris-git-r857.eb235f8-1-x86_64 +installed = libastal-mpris-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-network-git-r857.eb235f8-1-x86_64 +installed = libastal-network-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-notifd-git-r857.eb235f8-1-x86_64 +installed = libastal-notifd-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-powerprofiles-git-r857.eb235f8-1-x86_64 +installed = libastal-powerprofiles-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-river-git-r857.eb235f8-1-x86_64 +installed = libastal-river-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-tray-git-r857.eb235f8-1-x86_64 +installed = libastal-tray-git-debug-r857.eb235f8-1-x86_64 +installed = libastal-wireplumber-git-r857.eb235f8-1-x86_64 +installed = libastal-wireplumber-git-debug-r857.eb235f8-1-x86_64 +installed = libasyncns-1:0.8+r3+g68cd5af-3.2-x86_64_v3 +installed = libatasmart-0.19-7.1-x86_64_v3 +installed = libatomic-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libatomic_ops-7.8.2-2.1-x86_64_v3 +installed = libavc1394-0.5.4-7.1-x86_64_v3 +installed = libavif-1.3.0-5.1-x86_64_v3 +installed = libayatana-appindicator-0.5.94-1.1-x86_64_v3 +installed = libayatana-indicator-0.9.4-1.1-x86_64 +installed = libb2-0.98.1-3.1-x86_64 +installed = libblake3-1.8.3-1.1-x86_64_v3 +installed = libblockdev-3.4.0-2.1-x86_64_v3 +installed = libblockdev-crypto-3.4.0-2.1-x86_64_v3 +installed = libblockdev-fs-3.4.0-2.1-x86_64_v3 +installed = libblockdev-loop-3.4.0-2.1-x86_64_v3 +installed = libblockdev-mdraid-3.4.0-2.1-x86_64_v3 +installed = libblockdev-nvme-3.4.0-2.1-x86_64_v3 +installed = libblockdev-part-3.4.0-2.1-x86_64_v3 +installed = libblockdev-smart-3.4.0-2.1-x86_64_v3 +installed = libblockdev-swap-3.4.0-2.1-x86_64_v3 +installed = libbluray-1.4.0-2.1-x86_64_v3 +installed = libbpf-1.6.2-1.1-x86_64_v3 +installed = libbs2b-3.1.0-10.1-x86_64_v3 +installed = libbsd-0.12.2-2.1-x86_64 +installed = libbytesize-2.12-3.1-x86_64_v3 +installed = libc++-21.1.8-1.1-x86_64_v3 +installed = libc++abi-21.1.8-1.1-x86_64_v3 +installed = libcaca-0.99.beta20-6.1-x86_64_v3 +installed = libcacard-2.8.1-1.1-x86_64 +installed = libcanberra-1:0.30+r2+gc0620e4-6.1-x86_64_v3 +installed = libcap-2.77-1.1-x86_64_v3 +installed = libcap-ng-0.9-1.1-x86_64_v3 +installed = libcava-0.10.7-1-x86_64 +installed = libcava-debug-0.10.7-1-x86_64 +installed = libcbor-0.12.0-1.2-x86_64_v3 +installed = libcdio-2.3.0-1.1-x86_64_v3 +installed = libcdio-paranoia-10.2+2.0.2-1.2-x86_64 +installed = libcdr-0.1.8-4.1-x86_64_v3 +installed = libcerf-1:3.3-1.1-x86_64_v3 +installed = libcloudproviders-0.4.0-1.1-x86_64_v3 +installed = libcmis-0.6.2-7.1-x86_64_v3 +installed = libcolord-1.4.8-1-x86_64 +installed = libcpuid-0.8.1-1.1-x86_64_v3 +installed = libcups-2:2.4.16-2-x86_64 +installed = libcurl-compat-8.18.0-3.1-x86_64_v3 +installed = libcurl-gnutls-8.18.0-3.1-x86_64_v3 +installed = libdaemon-0.14-6.1-x86_64 +installed = libdatachannel-0.24.1-1.1-x86_64_v3 +installed = libdatrie-0.2.14-1.1-x86_64_v3 +installed = libdbusmenu-glib-18.10.20180917-1-x86_64 +installed = libdbusmenu-gtk2-16.04.0.r498-3-x86_64 +installed = libdbusmenu-gtk3-18.10.20180917-1-x86_64 +installed = libdbusmenu-qt5-0.9.3+16.04.20160218-7-x86_64 +installed = libdc1394-2.2.7-1.1-x86_64 +installed = libde265-1.0.16-2.1-x86_64_v3 +installed = libdecor-0.2.5-1.1-x86_64_v3 +installed = libdeflate-1.25-1.1-x86_64_v3 +installed = libdispatch-6.1-1.1-x86_64_v3 +installed = libdisplay-info-0.3.0-1.1-x86_64_v3 +installed = libdmtx-0.7.8-1.1-x86_64_v3 +installed = libdovi-3.3.2-1.1-x86_64_v3 +installed = libdrm-2.4.131-1.1-x86_64_v3 +installed = libdv-1.0.0-11.1-x86_64 +installed = libdvdnav-7.0.0-1.1-x86_64_v3 +installed = libdvdread-7.0.1-1.1-x86_64_v3 +installed = libe-book-0.1.3-20.1-x86_64_v3 +installed = libebur128-1.2.6-2.1-x86_64 +installed = libedit-20250104_3.1-1.1-x86_64_v3 +installed = libei-1.5.0-1.1-x86_64_v3 +installed = libelf-0.194-1-x86_64 +installed = libepoxy-1.5.10-3.1-x86_64 +installed = libepubgen-0.1.1-6.1-x86_64_v3 +installed = libestr-0.1.11-1-x86_64 +installed = libetonyek-0.1.13-2.1-x86_64_v3 +installed = libevdev-1.13.6-1.1-x86_64_v3 +installed = libevent-2.1.12-5.1-x86_64_v3 +installed = libexif-0.6.25-1.1-x86_64_v3 +installed = libexttextcat-3.4.7-1.1-x86_64 +installed = libfastjson-1.2304.0-1-x86_64 +installed = libfdk-aac-2.0.3-1.1-x86_64 +installed = libffi-3.5.2-1.1-x86_64_v3 +installed = libfido2-1.16.0-2.1-x86_64_v3 +installed = libfontenc-1.1.9-1.1-x86_64_v3 +installed = libfreeaptx-0.2.2-1.1-x86_64_v3 +installed = libfreehand-0.1.2-6.1-x86_64_v3 +installed = libfyaml-0.9.4-1.1-x86_64_v3 +installed = libgadu-1.12.2-14.1-x86_64 +installed = libgbinder-1.1.43-2.1-x86_64_v3 +installed = libgcc-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libgcrypt-1.12.1-1.1-x86_64_v3 +installed = libgcrypt15-1.5.6-7-x86_64 +installed = libgdiplus-6.2-1.1-x86_64_v3 +installed = libgexiv2-0.14.6-2.1-x86_64_v3 +installed = libgfortran-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libgig-4.5.2-1.1-x86_64_v3 +installed = libgirepository-1.86.0-2.1-x86_64_v3 +installed = libgit2-1:1.9.2-3.1-x86_64_v3 +installed = libglibutil-1.0.80-2.1-x86_64_v3 +installed = libglvnd-1.7.0-3.1-x86_64_v3 +installed = libgoa-3.56.4-1.1-x86_64_v3 +installed = libgomp-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libgpg-error-1.59-1.1-x86_64_v3 +installed = libgravatar-25.12.2-1.1-x86_64_v3 +installed = libgtop-2.41.3-2.1-x86_64 +installed = libgudev-238-3.1-x86_64_v3 +installed = libgweather-4-4.4.4-3.1-x86_64_v3 +installed = libhandy-1.8.3-2.1-x86_64 +installed = libheif-1.21.2-2.1-x86_64_v3 +installed = libibus-1.5.33-3.1-x86_64_v3 +installed = libical-3.0.20-3.1-x86_64_v3 +installed = libice-1.1.2-1.1-x86_64 +installed = libidn-1.43-1.1-x86_64_v3 +installed = libidn11-1.33-3-x86_64 +installed = libidn2-2.3.8-1.1-x86_64_v3 +installed = libiec61883-1.2.0-9.1-x86_64_v3 +installed = libimagequant-4.4.1-1-x86_64 +installed = libimobiledevice-1.4.0-2.1-x86_64_v3 +installed = libimobiledevice-glue-1.3.2-1.1-x86_64_v3 +installed = libindicator-gtk2-12.10.1-11-x86_64 +installed = libinih-61-1.1-x86_64_v3 +installed = libinput-1.30.1-1.1-x86_64_v3 +installed = libiscsi-1.20.3-1.1-x86_64_v3 +installed = libisl-0.27-1.1-x86_64 +installed = libixion-0.20.0-5.1-x86_64_v3 +installed = libjpeg-turbo-3.1.3-1.1-x86_64_v3 +installed = libjpeg6-turbo-1.5.3-3-x86_64 +installed = libjuice-1.7.0-1.1-x86_64_v3 +installed = libjxl-0.11.2-2.1-x86_64_v3 +installed = libkdcraw-25.12.2-1-x86_64 +installed = libkdepim-25.12.2-1.1-x86_64_v3 +installed = libkexiv2-25.12.2-1.1-x86_64_v3 +installed = libkgapi-25.12.2-1.1-x86_64_v3 +installed = libkleo-25.12.2-1.1-x86_64_v3 +installed = libkolabxml-1.3.1-7.1-x86_64_v3 +installed = libksba-1.6.7-2.1-x86_64_v3 +installed = libkscreen-6.6.0-1.1-x86_64_v3 +installed = libksysguard-6.6.0-1-x86_64 +installed = liblangtag-0.6.8-1.1-x86_64_v3 +installed = liblc3-1.1.3-2.1-x86_64_v3 +installed = libldac-2.0.2.3-2.1-x86_64 +installed = libldap-2.6.12-1-x86_64 +installed = libliftoff-0.5.0-1.1-x86_64 +installed = liblogging-1.0.6-3-x86_64 +installed = liblouis-3.36.0-2.1-x86_64_v3 +installed = liblphobos-3:1.41.0-2-x86_64 +installed = liblqr-0.4.3-1.1-x86_64 +installed = liblsan-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libluv-1.51.0-1.1-x86_64_v3 +installed = liblzf-3.6-5.1-x86_64 +installed = libmakepkg-dropins-20-1-any +installed = libmalcontent-0.13.1-1.1-x86_64_v3 +installed = libmanette-0.2.13-1.1-x86_64_v3 +installed = libmaxminddb-1.12.2-2.2-x86_64_v3 +installed = libmbim-1.34.0-1.1-x86_64_v3 +installed = libmd-1.1.0-2.1-x86_64 +installed = libmfx-23.2.2-6-x86_64 +installed = libmicrohttpd-1.0.2-1.1-x86_64_v3 +installed = libmikmod-3.3.13-1.1-x86_64_v3 +installed = libmm-glib-1.24.2-1.1-x86_64_v3 +installed = libmng-2.0.3-4.1-x86_64 +installed = libmnl-1.0.5-2.1-x86_64 +installed = libmodplug-0.8.9.0-6.1-x86_64 +installed = libmpc-1.3.1-2.1-x86_64 +installed = libmpdclient-2.23-1.1-x86_64_v3 +installed = libmpeg2-0.5.1-11.1-x86_64_v3 +installed = libmspack-1:1.11-1.2-x86_64_v3 +installed = libmspub-0.1.4-19.1-x86_64_v3 +installed = libmtp-1.1.23-1.1-x86_64_v3 +installed = libmupdf-1.27.2-1-x86_64 +installed = libmwaw-0.3.22-4.1-x86_64_v3 +installed = libmypaint-1.6.1-2.1-x86_64 +installed = libmysofa-1.3.3-1.1-x86_64 +installed = libndp-1.9-1.2-x86_64_v3 +installed = libnet-2:1.3-1.2-x86_64_v3 +installed = libnetfilter_conntrack-1.0.9-2.1-x86_64 +installed = libnewt-0.52.25-2.1-x86_64_v3 +installed = libnfnetlink-1.0.2-2.1-x86_64 +installed = libnfs-6.0.2-5.2-x86_64_v3 +installed = libnftnl-1.3.1-1.1-x86_64_v3 +installed = libnghttp2-1.68.0-1.1-x86_64_v3 +installed = libnghttp3-1.15.0-1.1-x86_64_v3 +installed = libngtcp2-1.20.0-1.1-x86_64_v3 +installed = libnice-0.1.23-1.1-x86_64_v3 +installed = libnl-3.12.0-1.1-x86_64_v3 +installed = libnm-1.54.3-1-x86_64 +installed = libnma-1.10.6-3.1-x86_64 +installed = libnma-common-1.10.6-3.1-x86_64 +installed = libnma-gtk4-1.10.6-3.1-x86_64 +installed = libnotify-0.8.8-1.1-x86_64_v3 +installed = libnsbmp-0.1.7-1.1-x86_64 +installed = libnsgif-1.0.0-1.1-x86_64 +installed = libnsl-2.0.1-1.1-x86_64 +installed = libnumbertext-1.0.11-3.1-x86_64_v3 +installed = libnvme-1.16.1-3.1-x86_64_v3 +installed = libobjc-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libodfgen-0.1.8-5.1-x86_64_v3 +installed = libogg-1.3.6-1.1-x86_64_v3 +installed = libolm-3.2.16-6.1-x86_64_v3 +installed = libopenmpt-0.8.4-1.1-x86_64_v3 +installed = liborcus-0.21.0-4.1-x86_64_v3 +installed = libp11-kit-0.26.2-1.1-x86_64_v3 +installed = libpagemaker-0.0.4-5.1-x86_64_v3 +installed = libpaper-2.2.7-1.1-x86_64_v3 +installed = libpcap-1.10.6-1.1-x86_64_v3 +installed = libpciaccess-0.18.1-2.1-x86_64 +installed = libpfm-4.13.0+r83+g91970fe-1.1-x86_64 +installed = libpgm-5.3.128-3.1-x86_64 +installed = libphonenumber-1:9.0.24-1.1-x86_64_v3 +installed = libpipeline-1.5.8-1.1-x86_64 +installed = libpipewire-1:1.4.10-2.1-x86_64_v3 +installed = libplacebo-7.360.0-1.1-x86_64_v3 +installed = libplasma-6.6.0-1.1-x86_64_v3 +installed = libplist-2.7.0-3.1-x86_64_v3 +installed = libpng-1.6.55-1.1-x86_64_v3 +installed = libpng12-1.2.59-2-x86_64 +installed = libportal-0.9.1-2.1-x86_64_v3 +installed = libportal-gtk4-0.9.1-2.1-x86_64_v3 +installed = libproxy-0.5.12-1.1-x86_64_v3 +installed = libpsl-0.21.5-2.1-x86_64 +installed = libpulse-17.0+r98+gb096704c0-1.1-x86_64_v3 +installed = libpurple-2.14.14-4-x86_64 +installed = libpwquality-1.4.5-7.1-x86_64_v3 +installed = libqaccessibilityclient-qt6-0.6.0-1-x86_64 +installed = libqalculate-5.9.0-1.1-x86_64_v3 +installed = libqmi-1.38.0-1.1-x86_64_v3 +installed = libqrtr-glib-1.4.0-1.1-x86_64_v3 +installed = libquadmath-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libqxp-0.0.2-15.1-x86_64_v3 +installed = libraqm-0.10.4-1.1-x86_64_v3 +installed = libraw-0.22.0-2.1-x86_64_v3 +installed = libraw1394-2.1.2-4.1-x86_64 +installed = librelp-1.10.0-1-x86_64 +installed = libreoffice-fresh-26.2.0-4.1-x86_64_v3 +installed = librevenge-0.0.5-4.1-x86_64_v3 +installed = librewolf-bin-1:147.0.4_1-1-x86_64 +installed = librist-0.2.11-1-x86_64 +installed = librsvg-2:2.61.4-1.1-x86_64_v3 +installed = librsync-1:2.3.4-2.1-x86_64 +installed = librtmp0-2.4-6-x86_64 +installed = libsamplerate-0.2.2-3.1-x86_64 +installed = libsasl-2.1.28-5.1-x86_64 +installed = libseccomp-2.6.0-1.1-x86_64_v3 +installed = libsecret-0.21.7-1.1-x86_64_v3 +installed = libshout-1:2.4.6-5.1-x86_64_v3 +installed = libsigc++-2.12.1-2.1-x86_64_v3 +installed = libsigc++-3.0-3.8.0-1.1-x86_64_v3 +installed = libsigc++-docs-2.12.1-2.1-x86_64_v3 +installed = libsixel-1.10.5-1.1-x86_64_v3 +installed = libslirp-4.9.1-1.1-x86_64_v3 +installed = libsm-1.2.6-1.2-x86_64_v3 +installed = libsndfile-1.2.2-4.1-x86_64_v3 +installed = libsodium-1.0.20-1.1-x86_64 +installed = libsolv-0.7.35-2.1-x86_64_v3 +installed = libsoup-2.74.3-4.1-x86_64_v3 +installed = libsoup3-3.6.6-1.1-x86_64_v3 +installed = libsoxr-0.1.3-4.1-x86_64 +installed = libspeechd-0.12.1-3.1-x86_64_v3 +installed = libspiro-1:20240903-1.2-x86_64_v3 +installed = libsrtp-1:2.7.0-1.1-x86_64_v3 +installed = libssh-0.12.0-1.1-x86_64_v3 +installed = libssh2-1.11.1-1.1-x86_64_v3 +installed = libstaroffice-0.0.7-5.1-x86_64_v3 +installed = libstdc++-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libstemmer-3.0.1-1.1-x86_64_v3 +installed = libsynctex-2025.2-3.1-x86_64_v3 +installed = libsysprof-capture-49.0-2.1-x86_64_v3 +installed = libtasn1-4.21.0-1.1-x86_64_v3 +installed = libtatsu-1.0.5-1.1-x86_64_v3 +installed = libteam-1.32-3.1-x86_64_v3 +installed = libtexprintf-git-main-3-x86_64 +installed = libtg_owt-0.git32.ec53225-2.1-x86_64_v3 +installed = libthai-0.1.30-1.1-x86_64_v3 +installed = libtheora-1.2.0-1.1-x86_64_v3 +installed = libtiff-4.7.1-1.1-x86_64_v3 +installed = libtiff4-3.9.7-8-x86_64 +installed = libtirpc-1.3.7-1.1-x86_64_v3 +installed = libtommath-1.3.0-2.1-x86_64_v3 +installed = libtool-2.6.0-4-x86_64 +installed = libtorrent-rasterbar-1:2.0.11-8.1-x86_64_v3 +installed = libtpms-0.10.2-1-x86_64 +installed = libtraceevent-1:1.8.7-1.1-x86_64_v3 +installed = libtracefs-1.8.3-1.1-x86_64_v3 +installed = libtsan-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libubsan-15.2.1+r604+g0b99615a8aef-2-x86_64_v3 +installed = libudev0-shim-2-2-x86_64 +installed = libunibreak-6.1-1.2-x86_64_v3 +installed = libuninameslist-20240910-1.1-x86_64 +installed = libunistring-1.4.1-1.1-x86_64_v3 +installed = libunwind-1.8.2-1.1-x86_64_v3 +installed = liburcu-0.15.5-1.1-x86_64_v3 +installed = liburing-2.14-1.1-x86_64_v3 +installed = libusb-1.0.29-1.1-x86_64_v3 +installed = libusbmuxd-2.1.1-2.1-x86_64_v3 +installed = libutempter-1.2.3-1.1-x86_64_v3 +installed = libutf8proc-2.11.3-1.1-x86_64_v3 +installed = libuv-1.52.0-1-x86_64 +installed = libva-2.22.0-1.1-x86_64 +installed = libva-nvidia-driver-0.0.15-1.1-x86_64_v3 +installed = libva-utils-2.22.0-1.1-x86_64 +installed = libvdpau-1.5-4.1-x86_64_v3 +installed = libverto-0.3.2-5.1-x86_64 +installed = libvisio-0.1.10-3.1-x86_64_v3 +installed = libvlc-3.0.21-32.1-x86_64_v3 +installed = libvorbis-1.3.7-4.1-x86_64_v3 +installed = libvpl-2.16.0-2.1-x86_64_v3 +installed = libvpx-1.15.2-3.1-x86_64_v3 +installed = libvpx1.3-1.3.0-4-x86_64 +installed = libwacom-2.18.0-2-x86_64 +installed = libwbclient-2:4.23.5-1.1-x86_64_v3 +installed = libwebp-1.6.0-2.1-x86_64_v3 +installed = libwireplumber-0.5.13-1.1-x86_64_v3 +installed = libwireplumber-4.0-compat-0.4.17-2-x86_64 +installed = libwmf-0.2.13-4.1-x86_64 +installed = libwpd-0.10.3-6.1-x86_64_v3 +installed = libwpg-0.3.4-3.1-x86_64_v3 +installed = libwps-0.4.14-4.1-x86_64_v3 +installed = libx11-1.8.13-1.1-x86_64_v3 +installed = libxau-1.0.12-1.1-x86_64 +installed = libxaw-1.0.16-1.1-x86_64 +installed = libxcb-1.17.0-1.2-x86_64_v3 +installed = libxcomposite-0.4.7-1.1-x86_64_v3 +installed = libxcrypt-4.5.2-1.1-x86_64_v3 +installed = libxcrypt-compat-4.5.2-1.1-x86_64_v3 +installed = libxcursor-1.2.3-1.1-x86_64 +installed = libxcvt-0.1.3-1.1-x86_64 +installed = libxdamage-1.1.7-1.1-x86_64_v3 +installed = libxdmcp-1.1.5-1.2-x86_64_v3 +installed = libxdp-1.6.2-1.1-x86_64_v3 +installed = libxext-1.3.7-1.1-x86_64_v3 +installed = libxfce4ui-4.20.2-1.1-x86_64_v3 +installed = libxfce4util-4.20.1-1.1-x86_64_v3 +installed = libxfixes-6.0.2-1.1-x86_64_v3 +installed = libxfont2-2.0.7-1.1-x86_64 +installed = libxft-2.3.9-1.2-x86_64_v3 +installed = libxi-1.8.2-1.1-x86_64 +installed = libxinerama-1.1.6-1.1-x86_64_v3 +installed = libxkbcommon-1.13.1-1.1-x86_64_v3 +installed = libxkbcommon-x11-1.13.1-1.1-x86_64_v3 +installed = libxkbfile-1.2.0-1.1-x86_64_v3 +installed = libxml2-2.15.1-5.1-x86_64_v3 +installed = libxml2-legacy-2.13.9-2.1-x86_64_v3 +installed = libxmlb-0.3.25-1.1-x86_64_v3 +installed = libxmp-4.6.3-1.1-x86_64_v3 +installed = libxmu-1.3.1-1.1-x86_64_v3 +installed = libxpm-3.5.18-1.1-x86_64_v3 +installed = libxpresent-1.0.2-1.1-x86_64_v3 +installed = libxrandr-1.5.5-1.1-x86_64_v3 +installed = libxrender-0.9.12-1.1-x86_64 +installed = libxres-1.2.3-1.1-x86_64_v3 +installed = libxshmfence-1.3.3-1.1-x86_64 +installed = libxslt-1.1.45-2.1-x86_64_v3 +installed = libxss-1.2.5-1.1-x86_64_v3 +installed = libxt-1.3.1-1.1-x86_64 +installed = libxtst-1.2.5-1.1-x86_64 +installed = libxv-1.0.13-1.1-x86_64 +installed = libxxf86vm-1.1.7-1.1-x86_64_v3 +installed = libyaml-0.2.5-3.1-x86_64 +installed = libyuv-r2426+464c51a03-1.1-x86_64 +installed = libzip-1.11.4-1.2-x86_64_v3 +installed = libzmf-0.0.2-20.1-x86_64_v3 +installed = licenses-20240728-1-any +installed = lilv-0.26.4-1-x86_64 +installed = limine-10.8.0-1-x86_64 +installed = limine-mkinitcpio-hook-1.30.0-1-x86_64 +installed = linux-6.18.9.arch1-2-x86_64 +installed = linux-api-headers-1:6.19-1-x86_64_v3 +installed = linux-cachyos-6.19.3-2-x86_64_v3 +installed = linux-cachyos-headers-6.19.3-2-x86_64_v3 +installed = linux-cachyos-nvidia-open-6.19.3-2-x86_64_v3 +installed = linux-firmware-1:20260110-1-any +installed = linux-firmware-amdgpu-1:20260110-1-any +installed = linux-firmware-atheros-1:20260110-1-any +installed = linux-firmware-broadcom-1:20260110-1-any +installed = linux-firmware-cirrus-1:20260110-1-any +installed = linux-firmware-intel-1:20260110-1-any +installed = linux-firmware-mediatek-1:20260110-1-any +installed = linux-firmware-nvidia-1:20260110-1-any +installed = linux-firmware-other-1:20260110-1-any +installed = linux-firmware-radeon-1:20260110-1-any +installed = linux-firmware-realtek-1:20260110-1-any +installed = linux-firmware-whence-1:20260110-1-any +installed = linux-tools-meta-6.19-2-x86_64 +installed = litehtml-0.9-2.1-x86_64_v3 +installed = llama.cpp-cuda-git-b7966-1-x86_64 +installed = lld-21.1.8-1.1-x86_64_v3 +installed = lld20-20.1.8-1.1-x86_64_v3 +installed = lldb-21.1.8-1.1-x86_64_v3 +installed = llhttp-9.3.1-1.1-x86_64_v3 +installed = llvm-21.1.8-2-x86_64_v3 +installed = llvm-libs-21.1.8-2-x86_64_v3 +installed = llvm20-libs-20.1.8-1.1-x86_64_v3 +installed = lm_sensors-1:3.6.2-1.1-x86_64_v3 +installed = lmdb-0.9.33-1.1-x86_64 +installed = lmms-1.2.2-27-x86_64 +installed = lostfiles-4.14-1-any +installed = lowdown-2.0.4-1.1-x86_64_v3 +installed = lpsolve-5.5.2.11-3.1-x86_64 +installed = lsb-release-2.0.r55.a25a4fc-1-any +installed = lshw-B.02.20-3.1-x86_64_v3 +installed = lsof-4.99.5-2.1-x86_64_v3 +installed = ltrace-0.7.3-6.1-x86_64_v3 +installed = lua-5.4.8-2.1-x86_64_v3 +installed = lua-argparse-0.7.1-2-any +installed = lua-filesystem-1.9.0-1.1-x86_64_v3 +installed = lua-luv-1.51.0-1.1-x86_64_v3 +installed = lua51-lpeg-1.1.0-4-x86_64 +installed = luacheck-1.2.0-2-any +installed = luajit-2.1.1767980792+707c12b-2.1-x86_64_v3 +installed = luarocks-3.13.0-1-any +installed = lutris-0.5.20-1-any +installed = lv2-1.18.10-2.1-x86_64_v3 +installed = lvm2-2.03.38-1.1-x86_64_v3 +installed = lxc-1:6.0.5-1.1-x86_64_v3 +installed = lynx-2.9.2-2.1-x86_64_v3 +installed = lz4-1:1.10.0-3-x86_64_v3 +installed = lzo-2.10-5.1-x86_64 +installed = m4-1.4.21-1.1-x86_64_v3 +installed = mailcap-2.1.54-2-any +installed = mailcommon-25.12.2-1.1-x86_64_v3 +installed = mailimporter-25.12.2-1.1-x86_64_v3 +installed = make-4.4.1-2.1-x86_64 +installed = mallard-ducktype-1.0.2-13-any +installed = man-db-2.13.1-1.1-x86_64_v3 +installed = man-pages-6.17-1-any +installed = mangohud-0.8.2-3.1-x86_64_v3 +installed = mangowc-git-r1276.9b92f13-1-x86_64 +installed = mariadb-12.2.2-2.1-x86_64_v3 +installed = mariadb-clients-12.2.2-2.1-x86_64_v3 +installed = mariadb-libs-12.2.2-2.1-x86_64_v3 +installed = mbedtls-3.6.5-1-x86_64 +installed = mbedtls2-2.28.10-1.1-x86_64_v3 +installed = md4c-0.5.2-1.1-x86_64 +installed = mdadm-4.4-2-x86_64 +installed = media-player-info-26-1-any +installed = merkuro-25.12.2-1.1-x86_64_v3 +installed = mermaid-cli-11.12.0-1-any +installed = mesa-1:25.3.5-2-x86_64 +installed = mesa-utils-9.0.0-7.1-x86_64_v3 +installed = meson-1.10.1-1-any +installed = messagelib-25.12.2-1.1-x86_64_v3 +installed = milou-6.6.0-1.1-x86_64_v3 +installed = mimetreeparser-25.12.2-1.1-x86_64_v3 +installed = mingw-w64-binutils-2.45.1-1.1-x86_64_v3 +installed = mingw-w64-crt-13.0.0-1-any +installed = mingw-w64-gcc-15.2.0-1.1-x86_64_v3 +installed = mingw-w64-headers-13.0.0-1-any +installed = mingw-w64-winpthreads-13.0.0-1-any +installed = miniconda3-25.11.1.1-1-x86_64 +installed = miniupnpc-2.3.3-3.1-x86_64_v3 +installed = minizip-1:1.3.2-2.1-x86_64_v3 +installed = mission-center-1.1.0-1.1-x86_64_v3 +installed = mkinitcpio-40-5-any +installed = mkinitcpio-busybox-1.36.1-1.1-x86_64 +installed = mm-common-1.0.7-1-any +installed = mobile-broadband-provider-info-20251101-1-any +installed = modemmanager-1.24.2-1.1-x86_64_v3 +installed = modemmanager-qt-6.23.0-1.1-x86_64_v3 +installed = mono-6.12.0.206-1.1-x86_64 +installed = mpdecimal-4.0.1-1.1-x86_64_v3 +installed = mpfr-4.2.2-1.1-x86_64_v3 +installed = mpg123-1.33.4-1.1-x86_64_v3 +installed = mpv-1:0.41.0-3.1-x86_64_v3 +installed = msgpack-c-6.1.0-2.1-x86_64 +installed = msgpack-cxx-7.0.0-1-any +installed = mtdev-1.1.7-1.1-x86_64 +installed = mtools-1:4.0.49-1.1-x86_64_v3 +installed = mtxclient-0.10.1-4.1-x86_64_v3 +installed = mujs-1.3.8-1.1-x86_64_v3 +installed = multipath-tools-0.14.3-1.1-x86_64_v3 +installed = muparser-2.3.5-2.1-x86_64_v3 +installed = mxml-3.3.1-2.1-x86_64 +installed = mypaint-brushes1-1.3.1-2-any +installed = namcap-3.6.0-3-any +installed = nano-8.7.1-1.1-x86_64_v3 +installed = nasm-3.01-1.1-x86_64_v3 +installed = ncdu-2.9.2-1.1-x86_64_v3 +installed = ncurses-6.6-1.1-x86_64_v3 +installed = ndctl-79-1.1-x86_64 +installed = neon-0.36.0-1-x86_64 +installed = neovim-git-0.12.0.r2398.g2478a7fbbd-1-x86_64 +installed = net-snmp-5.9.5.2-1.1-x86_64_v3 +installed = net-tools-2.10-3.1-x86_64 +installed = netpbm-10.86.48-1.1-x86_64_v3 +installed = nettle-3.10.2-1.1-x86_64_v3 +installed = network-manager-applet-1.36.0-1-x86_64 +installed = networkmanager-1.54.3-1-x86_64 +installed = networkmanager-openvpn-1.12.5-1.1-x86_64_v3 +installed = networkmanager-qt-6.23.0-1.1-x86_64_v3 +installed = networkmanager-vpn-plugin-openvpn-1.12.5-1.1-x86_64_v3 +installed = nftables-1:1.1.6-2.1-x86_64_v3 +installed = nginx-1.28.2-1.1-x86_64_v3 +installed = nheko-0.12.1-7.1-x86_64_v3 +installed = ninja-1.13.2-3.1-x86_64_v3 +installed = niri-25.11-1.1-x86_64_v3 +installed = nix-2.33.3-2.1-x86_64_v3 +installed = nix-busybox-1.36.1-2-x86_64 +installed = nlohmann-json-3.12.0-2-any +installed = nm-connection-editor-1.36.0-1-x86_64 +installed = nmap-7.98-5-x86_64 +installed = node-gyp-12.2.0-1-any +installed = nodejs-25.6.1-2.1-x86_64_v3 +installed = nodejs-nopt-7.2.1-1-any +installed = noto-fonts-1:2026.02.01-1-any +installed = noto-fonts-cjk-20240730-1-any +installed = noto-fonts-emoji-1:2.051-1-any +installed = npm-11.10.1-1-any +installed = npth-1.8-1.1-x86_64 +installed = nspr-4.38.2-1.1-x86_64_v3 +installed = nss-3.120.1-1.1-x86_64_v3 +installed = ntfs-3g-2022.10.3-2.1-x86_64_v3 +installed = numactl-2.0.19-1-x86_64 +installed = nvibrant-bin-1.1.0-1-x86_64 +installed = nvidia-utils-590.48.01-6-x86_64_v3 +installed = nvme-cli-2.16-2-x86_64 +installed = nvtop-3.3.2-1.1-x86_64_v3 +installed = nwg-dock-hyprland-0.4.8-4.1-x86_64_v3 +installed = nwg-look-1.0.6-1.1-x86_64_v3 +installed = nyx-2.1.0-10-any +installed = obs-pipewire-audio-capture-1.2.1-1-x86_64 +installed = obs-studio-32.0.4-1.1-x86_64_v3 +installed = ocean-sound-theme-6.6.0-1-any +installed = ocl-icd-2.3.4-1.1-x86_64_v3 +installed = oh-my-posh-bin-29.6.1-1-x86_64 +installed = ollama-0.17.0-1.1-x86_64_v3 +installed = ollama-cuda-0.17.0-1.1-x86_64_v3 +installed = onetbb-2022.3.0-4-x86_64 +installed = oniguruma-6.9.10-1.1-x86_64_v3 +installed = onnx-1:1.20.1-1.1-x86_64_v3 +installed = openal-1.25.1-1.1-x86_64_v3 +installed = openbsd-netcat-1.234_1-1.1-x86_64_v3 +installed = opencl-nvidia-590.48.01-6-x86_64_v3 +installed = opencode-bin-1.2.10-1-x86_64 +installed = opencore-amr-0.1.6-2.1-x86_64 +installed = opencv-4.13.0-2.1-x86_64_v3 +installed = openexr-3.4.5-1.1-x86_64_v3 +installed = openh264-2.6.0-2.1-x86_64_v3 +installed = openjpeg2-2.5.4-1.1-x86_64_v3 +installed = openrgb-1.0rc2-5.1-x86_64_v3 +installed = openslide-4.0.0-5.1-x86_64_v3 +installed = openssh-10.2p1-2.1-x86_64_v3 +installed = openssl-3.6.1-1.1-x86_64_v3 +installed = openssl-1.0-1.0.2.u-7-x86_64 +installed = openssl-1.1-1.1.1.w-9-x86_64 +installed = openvpn-2.7.0-1.1-x86_64_v3 +installed = openxr-1.1.57-1.1-x86_64_v3 +installed = opus-1.6.1-1.1-x86_64_v3 +installed = opusfile-0.12-4.1-x86_64 +installed = orc-0.4.42-1.1-x86_64_v3 +installed = os-prober-1.84-1.1-x86_64_v3 +installed = ostree-2025.7-2.1-x86_64_v3 +installed = otf-font-awesome-7.2.0-1-any +installed = otf-monaspace-nerdfonts-1.301-1-any +installed = otf-rubik-2.2.0-2-any +installed = oxygen-6.6.0-2.1-x86_64_v3 +installed = oxygen-cursors-6.6.0-2.1-x86_64_v3 +installed = oxygen-sounds-6.6.0-1-any +installed = p11-kit-0.26.2-1.1-x86_64_v3 +installed = pacman-7.1.0.r9.g54d9411-2-x86_64 +installed = pacman-contrib-1.13.1-1.2-x86_64_v3 +installed = pacman-mirrorlist-20260213-1-any +installed = pacseek-1.8.6-1-any +installed = pacutils-0.15.0-3-x86_64 +installed = pahole-1:1.31-2.1-x86_64_v3 +installed = pam-1.7.2-2.1-x86_64_v3 +installed = pambase-20250719-1-any +installed = pango-1:1.57.0-2.1-x86_64_v3 +installed = pangomm-2.46.4-1.4-x86_64_v3 +installed = pangomm-2.48-2.56.1-1.2-x86_64_v3 +installed = papirus-icon-theme-20250501-1-any +installed = parted-3.6-2.1-x86_64 +installed = patch-2.8-1.1-x86_64_v3 +installed = patchelf-0.18.0-4.1-x86_64_v3 +installed = patool-4.0.4-1-any +installed = pavucontrol-1:6.2-1.1-x86_64_v3 +installed = pciutils-3.14.0-1.1-x86_64_v3 +installed = pcre-8.45-4.1-x86_64 +installed = pcre2-10.47-1.1-x86_64_v3 +installed = pcsclite-2.4.1-1.1-x86_64_v3 +installed = pdftk-3.3.3-4-any +installed = perf-6.19-2-x86_64 +installed = perl-5.42.0-1.1-x86_64_v3 +installed = perl-alien-build-2.84-4-any +installed = perl-alien-libxml2-0.20-5-any +installed = perl-capture-tiny-0.50-4-any +installed = perl-clone-0.47-2.1-x86_64_v3 +installed = perl-encode-locale-1.05-15-any +installed = perl-error-0.17030-3-any +installed = perl-ffi-checklib-0.31-8-any +installed = perl-file-chdir-0.1011-6-any +installed = perl-file-homedir-1.006-8-any +installed = perl-file-listing-6.16-6-any +installed = perl-file-which-1.27-8-any +installed = perl-html-parser-3.83-2.1-x86_64_v3 +installed = perl-html-tagset-3.24-4-any +installed = perl-http-cookiejar-0.014-5-any +installed = perl-http-cookies-6.11-4-any +installed = perl-http-daemon-6.16-6-any +installed = perl-http-date-6.06-5-any +installed = perl-http-message-7.01-2-any +installed = perl-http-negotiate-6.01-16-any +installed = perl-image-exiftool-13.50-1-any +installed = perl-io-html-1.004-8-any +installed = perl-libwww-6.81-2-any +installed = perl-lwp-mediatypes-6.04-8-any +installed = perl-mailtools-2.22-3-any +installed = perl-net-http-6.24-2-any +installed = perl-path-tiny-0.150-2-any +installed = perl-timedate-2.33-9-any +installed = perl-try-tiny-0.32-4-any +installed = perl-uri-5.34-2-any +installed = perl-www-robotrules-6.02-16-any +installed = perl-xml-libxml-2.0210-4.1-x86_64_v3 +installed = perl-xml-namespacesupport-1.12-6-any +installed = perl-xml-parser-2.47-3.1-x86_64_v3 +installed = perl-xml-sax-1.02-2-any +installed = perl-xml-sax-base-1.09-6-any +installed = perl-yaml-tiny-1.76-3-any +installed = pidgin-2.14.14-4-x86_64 +installed = pimcommon-25.12.2-1.1-x86_64_v3 +installed = pinentry-1.3.2-2.1-x86_64_v3 +installed = pipewire-1:1.4.10-2.1-x86_64_v3 +installed = pipewire-alsa-1:1.4.10-2.1-x86_64_v3 +installed = pipewire-audio-1:1.4.10-2.1-x86_64_v3 +installed = pipewire-jack-1:1.4.10-2.1-x86_64_v3 +installed = pipewire-pulse-1:1.4.10-2.1-x86_64_v3 +installed = pixman-0.46.4-1.1-x86_64_v3 +installed = pkcs11-helper-1.31.0-1.1-x86_64_v3 +installed = pkgconf-2.5.1-1.1-x86_64_v3 +installed = pkgfile-25-2.1-x86_64_v3 +installed = plasma-activities-6.6.0-1.1-x86_64_v3 +installed = plasma-activities-stats-6.6.0-1.1-x86_64_v3 +installed = plasma-browser-integration-6.6.0-1.1-x86_64_v3 +installed = plasma-desktop-6.6.0-1.1-x86_64_v3 +installed = plasma-disks-6.6.0-1.1-x86_64_v3 +installed = plasma-firewall-6.6.0-1.1-x86_64_v3 +installed = plasma-integration-6.6.0-1.1-x86_64_v3 +installed = plasma-nm-6.6.0-1.1-x86_64_v3 +installed = plasma-sdk-6.6.0-1.1-x86_64_v3 +installed = plasma-systemmonitor-6.6.0-1.1-x86_64_v3 +installed = plasma-thunderbolt-6.6.0-1.1-x86_64_v3 +installed = plasma-vault-6.6.0-1.1-x86_64_v3 +installed = plasma-wayland-protocols-1.20.0-1-any +installed = plasma-welcome-6.6.0-1.1-x86_64_v3 +installed = plasma-workspace-6.6.0-1.1-x86_64_v3 +installed = plasma5support-6.6.0-1.1-x86_64_v3 +installed = playerctl-2.4.1-5.1-x86_64_v3 +installed = plocate-1.1.24-1.1-x86_64_v3 +installed = plymouth-24.004.60-14.1-x86_64_v3 +installed = plymouth-kcm-6.6.0-1.1-x86_64_v3 +installed = pnpm-10.28.2-1-any +installed = polkit-127-3.1-x86_64_v3 +installed = polkit-kde-agent-6.6.0-1.1-x86_64_v3 +installed = polkit-qt5-0.200.0-1-x86_64 +installed = polkit-qt6-0.200.0-1-x86_64 +installed = poppler-26.01.0-1.1-x86_64_v3 +installed = poppler-data-0.4.12-2-any +installed = poppler-glib-26.01.0-1.1-x86_64_v3 +installed = poppler-qt6-26.01.0-1.1-x86_64_v3 +installed = popt-1.19-2.1-x86_64 +installed = portaudio-1:19.7.0-3.2-x86_64 +installed = postgresql-libs-18.2-1.1-x86_64_v3 +installed = potrace-1.16-4.1-x86_64_v3 +installed = power-profiles-daemon-0.30-3-x86_64 +installed = powerdevil-6.6.0-1.1-x86_64_v3 +installed = powertop-2.15-2.1-x86_64 +installed = ppp-2.5.2-1.1-x86_64_v3 +installed = pps-tools-1.0.3-2.1-x86_64 +installed = prettier-3.7.3-1-any +installed = print-manager-1:6.6.0-1.1-x86_64_v3 +installed = prison-6.23.0-1.1-x86_64_v3 +installed = procps-ng-4.0.6-1.1-x86_64_v3 +installed = profile-sync-daemon-1:6.55-1-any +installed = protobuf-33.1-3.1-x86_64_v3 +installed = protobuf-c-1.5.2-8.1-x86_64_v3 +installed = proton-cachyos-1:10.0.20260207-3-x86_64 +installed = proton-cachyos-slr-1:10.0.20260207-1-x86_64 +installed = proton-mail-bin-1.12.1-1-any +installed = protontricks-1.13.1-3-any +installed = protonup-git-0.1.5.r4.g4ff9d54-2-any +installed = psmisc-23.7-1.1-x86_64 +installed = pugixml-1.15-3.1-x86_64_v3 +installed = purpose-6.23.0-1.1-x86_64_v3 +installed = putty-0.83-1.1-x86_64_v3 +installed = pwvucontrol-0.5.1-1-x86_64 +installed = pyalpm-0.11.1-1.1-x86_64_v3 +installed = python-3.14.3-2-x86_64_v3 +installed = python-acme-5.3.1-1-any +installed = python-annotated-doc-0.0.4-2-any +installed = python-annotated-types-0.7.0-3-any +installed = python-anyio-4.12.1-1-any +installed = python-appdirs-1.4.4-12-any +installed = python-argcomplete-3.6.2-2-any +installed = python-attrs-25.4.0-3-any +installed = python-autocommand-2.2.2-9-any +installed = python-babel-2.17.0-3-any +installed = python-beautifulsoup4-4.14.3-2-any +installed = python-boolean.py-5.0-2-any +installed = python-bsdiff4-1.2.6-2-x86_64 +installed = python-btrfs-15-2-any +installed = python-build-1.4.0-1-any +installed = python-cachecontrol-1:0.14.4-3-any +installed = python-cairo-1.29.0-2.1-x86_64_v3 +installed = python-cbor2-5.8.0-2.1-x86_64_v3 +installed = python-certifi-2026.01.04-1-any +installed = python-cffi-2.0.0-2.1-x86_64_v3 +installed = python-chardet-5.2.0-7-any +installed = python-charset-normalizer-3.4.4-2.1-x86_64_v3 +installed = python-click-8.3.1-1-any +installed = python-cloudflare-2.15.0-2-any +installed = python-colorama-0.4.6-6-any +installed = python-configargparse-1.7.1-1-any +installed = python-configobj-5.0.9-6-any +installed = python-contourpy-1.3.3-3.1-x86_64_v3 +installed = python-cryptography-46.0.5-2.1-x86_64_v3 +installed = python-cssselect-1.4.0-1-any +installed = python-cycler-0.12.1-4-any +installed = python-cymem-2.0.10-1.1-x86_64_v3 +installed = python-darkdetect-0.8.0-5-any +installed = python-dateutil-2.9.0-8-any +installed = python-dbus-1.4.0-2-x86_64 +installed = python-distlib-0.4.0-2-any +installed = python-distro-1.9.0-4-any +installed = python-docutils-1:0.22.3-2-any +installed = python-dulwich-0.25.2-1.1-x86_64_v3 +installed = python-editables-0.5-7-any +installed = python-evdev-1.9.3-1.1-x86_64_v3 +installed = python-fastbencode-0.3.9-2.2-x86_64_v3 +installed = python-fastjsonschema-2.21.2-2-any +installed = python-filelock-3.24.0-1-any +installed = python-filetype-1.2.0-7-any +installed = python-findsystemfontsfilename-0.3.3-1-any +installed = python-fonttools-4.61.1-2.1-x86_64_v3 +installed = python-fvs-0.3.4-5-any +installed = python-gbinder-1.3.1-1.1-x86_64_v3 +installed = python-gitdb-1:4.0.12-2-any +installed = python-gitpython-3.1.46-2-any +installed = python-gobject-3.54.5-2-x86_64 +installed = python-gpgme-2.0.0-2.1-x86_64_v3 +installed = python-h11-0.16.0-2-any +installed = python-hatch-1.16.3-1-any +installed = python-hatch-vcs-0.5.0-4-any +installed = python-hatchling-1.28.0-3-any +installed = python-httpcore-1.0.9-3-any +installed = python-httpx-0.28.1-7-any +installed = python-hwdata-2.4.3-2-any +installed = python-hyperlink-21.0.0-8-any +installed = python-idna-3.11-2-any +installed = python-ijson-3.4.0-2.1-x86_64_v3 +installed = python-imagesize-1.4.1-7-any +installed = python-installer-0.7.0-14-any +installed = python-jack-client-0.5.5-3-any +installed = python-jaraco.classes-3.4.0-3-any +installed = python-jaraco.collections-5.1.0-3-any +installed = python-jaraco.context-6.0.1-3-any +installed = python-jaraco.functools-4.1.0-3-any +installed = python-jaraco.text-4.0.0-4-any +installed = python-jeepney-0.9.0-3-any +installed = python-jellyfish-1.2.1-2.1-x86_64_v3 +installed = python-jinja-1:3.1.6-3-any +installed = python-josepy-2.2.0-2-any +installed = python-jsonlines-4.0.0-5-any +installed = python-keyring-25.7.0-3-any +installed = python-keyrings-alt-1:5.0.2-3-any +installed = python-kivy-2.3.1-2.1-x86_64_v3 +installed = python-kiwisolver-1.4.7-2.1-x86_64_v3 +installed = python-lark-parser-1.3.1-2-any +installed = python-license-expression-30.4.4-2-any +installed = python-linkify-it-py-2.0.3-6-any +installed = python-lockfile-0.12.2-15-any +installed = python-loguru-0.7.3-2-any +installed = python-lxml-6.0.2-2.1-x86_64_v3 +installed = python-mako-1.3.10-4-any +installed = python-markdown-3.10.2-1-any +installed = python-markdown-it-py-4.0.0-2-any +installed = python-markupsafe-3.0.2-2.1-x86_64_v3 +installed = python-materialyoucolor-2.0.10-1-x86_64 +installed = python-matplotlib-3.10.8-5-x86_64 +installed = python-mdurl-0.1.2-9-any +installed = python-merge3-0.0.16-2-any +installed = python-moddb-0.14.0-2-any +installed = python-more-itertools-10.8.0-2-any +installed = python-msgpack-1.1.2-2.1-x86_64_v3 +installed = python-mutagen-1.47.0-4-any +installed = python-numpy-2.4.2-1.1-x86_64_v3 +installed = python-orjson-3.11.7-1.1-x86_64_v3 +installed = python-packaging-26.0-1-any +installed = python-parsedatetime-2.6-11-any +installed = python-pathspec-1.0.4-1-any +installed = python-pathvalidate-3.3.1-2-any +installed = python-patiencediff-0.2.18-2.1-x86_64_v3 +installed = python-pefile-2024.8.26-2-any +installed = python-pexpect-4.9.0-7-any +installed = python-pillow-12.1.1-1-x86_64 +installed = python-pip-26.0.1-1-any +installed = python-pipenv-2026.0.2-2-any +installed = python-pipx-1.8.0-2-any +installed = python-pkg_resources-81.0.0-1-any +installed = python-platformdirs-4.9.2-1-any +installed = python-pluggy-1.6.0-3-any +installed = python-poetry-core-2.3.1-1-any +installed = python-polib-1.2.0-4-any +installed = python-psutil-7.2.2-1.1-x86_64_v3 +installed = python-ptyprocess-0.7.0-9-any +installed = python-pyalsaaudio-0.11.0-1-x86_64 +installed = python-pycparser-2.23-2-any +installed = python-pycryptodomex-3.23.0-2.1-x86_64_v3 +installed = python-pycurl-7.45.7-3.1-x86_64_v3 +installed = python-pydantic-2.12.5-4-any +installed = python-pydantic-core-3:2.41.5-3.1-x86_64_v3 +installed = python-pyelftools-0.32-2-any +installed = python-pygments-2.19.2-3-any +installed = python-pyinotify-0.9.6-16-any +installed = python-pynacl-1.6.2-1.1-x86_64_v3 +installed = python-pyopenssl-25.3.0-2-any +installed = python-pyparsing-3.3.2-1-any +installed = python-pyparted-3.13.0-6.1-x86_64_v3 +installed = python-pyperclipimg-0.2.0-2-any +installed = python-pyproject-hooks-1.2.0-6-any +installed = python-pyqt5-5.15.11-5-x86_64 +installed = python-pyqt5-sip-12.18.0-1.1-x86_64_v3 +installed = python-pyqt6-6.10.2-3-x86_64 +installed = python-pyqt6-sip-13.11.0-1.1-x86_64_v3 +installed = python-pyrfc3339-1.1-16-any +installed = python-pyserial-3.5-8-any +installed = python-pysocks-1.7.1-11-any +installed = python-pytz-2025.2-2-any +installed = python-pyudev-0.24.4-1-any +installed = python-pywayland-0.4.18-3.1-x86_64_v3 +installed = python-pyxdg-0.28-7-any +installed = python-pyzstd-0.19.1-3.1-x86_64_v3 +installed = python-requests-2.32.5-3-any +installed = python-rich-14.3.3-1-any +installed = python-roman-numerals-py-3.1.0-2-any +installed = python-schema-0.7.8-2-any +installed = python-secretstorage-3.3.3-7-any +installed = python-semantic-version-2.10.0-9-any +installed = python-send2trash-1.8.3-3-any +installed = python-setproctitle-1.3.7-2.1-x86_64_v3 +installed = python-setuptools-1:82.0.0-1-any +installed = python-setuptools-scm-9.2.2-3-any +installed = python-shellingham-1.5.4-4-any +installed = python-shtab-1.8.0-2-any +installed = python-six-1.17.0-2-any +installed = python-smmap-1:6.0.0-3-any +installed = python-snowballstemmer-2.2.0-8-any +installed = python-soupsieve-2.8.3-1-any +installed = python-sphinx-8.2.3-4-any +installed = python-sphinx-alabaster-theme-1.0.0-6-any +installed = python-sphinxcontrib-applehelp-2.0.0-5-any +installed = python-sphinxcontrib-devhelp-2.0.0-6-any +installed = python-sphinxcontrib-htmlhelp-2.1.0-5-any +installed = python-sphinxcontrib-jsmath-1.0.1-21-any +installed = python-sphinxcontrib-qthelp-2.0.0-5-any +installed = python-sphinxcontrib-serializinghtml-2.0.0-5-any +installed = python-steamgriddb-1.0.5-5-any +installed = python-stem-1.8.3-4-any +installed = python-systemd-235-5.1-x86_64_v3 +installed = python-termcolor-3.3.0-1-any +installed = python-textual-8.0.0-1-any +installed = python-tinycss2-1.5.1-2-any +installed = python-toml-0.10.2-13-any +installed = python-tomli-w-1.2.0-2-any +installed = python-tomlkit-0.14.0-1-any +installed = python-tqdm-4.67.3-1-any +installed = python-trove-classifiers-2026.1.14.14-1-any +installed = python-ttkbootstrap-1.20.1-1-any +installed = python-typer-0.24.1-1-any +installed = python-typing-inspection-0.4.2-2-any +installed = python-typing_extensions-4.15.0-3-any +installed = python-uc-micro-py-1.0.3-4-any +installed = python-urllib3-2.6.3-1-any +installed = python-userpath-1.9.2-4-any +installed = python-uv-0.10.4-1.1-x86_64_v3 +installed = python-vdf-4.0-5-any +installed = python-virtualenv-20.36.1-1-any +installed = python-virtualenv-clone-0.5.7-7-any +installed = python-wand-0.6.11-6-any +installed = python-watchdog-6.0.0-2-any +installed = python-webencodings-0.5.1-13-any +installed = python-websockets-16.0-1.1-x86_64_v3 +installed = python-wheel-0.46.3-1-any +installed = python-xlib-0.33-6-any +installed = python-xxhash-3.6.0-2.1-x86_64_v3 +installed = python-yaml-6.0.3-2.1-x86_64_v3 +installed = python-yara-4.5.4-1.1-x86_64_v3 +installed = python-zstandard-0.25.0-2.1-x86_64_v3 +installed = python2-2.7.18-12-x86_64 +installed = python311-3.11.14-1-x86_64 +installed = qbittorrent-5.1.4-1-x86_64 +installed = qca-qt6-2.3.10-4-x86_64 +installed = qcoro-0.13.0-1-x86_64 +installed = qemu-audio-alsa-10.2.0-3-x86_64 +installed = qemu-audio-dbus-10.2.0-3-x86_64 +installed = qemu-audio-jack-10.2.0-3-x86_64 +installed = qemu-audio-oss-10.2.0-3-x86_64 +installed = qemu-audio-pa-10.2.0-3-x86_64 +installed = qemu-audio-pipewire-10.2.0-3-x86_64 +installed = qemu-audio-sdl-10.2.0-3-x86_64 +installed = qemu-audio-spice-10.2.0-3-x86_64 +installed = qemu-base-10.2.0-3-x86_64 +installed = qemu-block-curl-10.2.0-3-x86_64 +installed = qemu-block-dmg-10.2.0-3-x86_64 +installed = qemu-block-gluster-10.2.0-3-x86_64 +installed = qemu-block-iscsi-10.2.0-3-x86_64 +installed = qemu-block-nfs-10.2.0-3-x86_64 +installed = qemu-block-ssh-10.2.0-3-x86_64 +installed = qemu-chardev-baum-10.2.0-3-x86_64 +installed = qemu-chardev-spice-10.2.0-3-x86_64 +installed = qemu-common-10.2.0-3-x86_64 +installed = qemu-desktop-10.2.0-3-x86_64 +installed = qemu-docs-10.2.0-3-x86_64 +installed = qemu-emulators-full-10.2.0-3-x86_64 +installed = qemu-full-10.2.0-3-x86_64 +installed = qemu-hw-display-qxl-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-gpu-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-gpu-gl-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-gpu-pci-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-gpu-pci-gl-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-gpu-pci-rutabaga-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-gpu-rutabaga-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-vga-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-vga-gl-10.2.0-3-x86_64 +installed = qemu-hw-display-virtio-vga-rutabaga-10.2.0-3-x86_64 +installed = qemu-hw-s390x-virtio-gpu-ccw-10.2.0-3-x86_64 +installed = qemu-hw-uefi-vars-10.2.0-3-x86_64 +installed = qemu-hw-usb-host-10.2.0-3-x86_64 +installed = qemu-hw-usb-redirect-10.2.0-3-x86_64 +installed = qemu-hw-usb-smartcard-10.2.0-3-x86_64 +installed = qemu-img-10.2.0-3-x86_64 +installed = qemu-pr-helper-10.2.0-3-x86_64 +installed = qemu-system-aarch64-10.2.0-3-x86_64 +installed = qemu-system-alpha-10.2.0-3-x86_64 +installed = qemu-system-alpha-firmware-10.2.0-3-x86_64 +installed = qemu-system-arm-10.2.0-3-x86_64 +installed = qemu-system-arm-firmware-10.2.0-3-x86_64 +installed = qemu-system-avr-10.2.0-3-x86_64 +installed = qemu-system-hppa-10.2.0-3-x86_64 +installed = qemu-system-hppa-firmware-10.2.0-3-x86_64 +installed = qemu-system-loongarch64-10.2.0-3-x86_64 +installed = qemu-system-m68k-10.2.0-3-x86_64 +installed = qemu-system-microblaze-10.2.0-3-x86_64 +installed = qemu-system-microblaze-firmware-10.2.0-3-x86_64 +installed = qemu-system-mips-10.2.0-3-x86_64 +installed = qemu-system-or1k-10.2.0-3-x86_64 +installed = qemu-system-ppc-10.2.0-3-x86_64 +installed = qemu-system-ppc-firmware-10.2.0-3-x86_64 +installed = qemu-system-riscv-10.2.0-3-x86_64 +installed = qemu-system-riscv-firmware-10.2.0-3-x86_64 +installed = qemu-system-rx-10.2.0-3-x86_64 +installed = qemu-system-s390x-10.2.0-3-x86_64 +installed = qemu-system-s390x-firmware-10.2.0-3-x86_64 +installed = qemu-system-sh4-10.2.0-3-x86_64 +installed = qemu-system-sparc-10.2.0-3-x86_64 +installed = qemu-system-sparc-firmware-10.2.0-3-x86_64 +installed = qemu-system-tricore-10.2.0-3-x86_64 +installed = qemu-system-x86-10.2.0-3-x86_64 +installed = qemu-system-x86-firmware-10.2.0-3-x86_64 +installed = qemu-system-xtensa-10.2.0-3-x86_64 +installed = qemu-tests-10.2.0-3-x86_64 +installed = qemu-tools-10.2.0-3-x86_64 +installed = qemu-ui-curses-10.2.0-3-x86_64 +installed = qemu-ui-dbus-10.2.0-3-x86_64 +installed = qemu-ui-egl-headless-10.2.0-3-x86_64 +installed = qemu-ui-gtk-10.2.0-3-x86_64 +installed = qemu-ui-opengl-10.2.0-3-x86_64 +installed = qemu-ui-sdl-10.2.0-3-x86_64 +installed = qemu-ui-spice-app-10.2.0-3-x86_64 +installed = qemu-ui-spice-core-10.2.0-3-x86_64 +installed = qemu-user-10.2.0-3-x86_64 +installed = qemu-user-static-10.2.0-3-x86_64 +installed = qemu-user-static-binfmt-10.2.0-3-x86_64 +installed = qemu-vhost-user-gpu-10.2.0-3-x86_64 +installed = qemu-vmsr-helper-10.2.0-3-x86_64 +installed = qgpgme-2.0.0-2.1-x86_64_v3 +installed = qhull-2020.2-5.1-x86_64 +installed = qoi-r350.4461cc3-1-any +installed = qqc2-breeze-style-6.6.0-1.1-x86_64_v3 +installed = qqc2-desktop-style-6.23.0-2.1-x86_64_v3 +installed = qqc2-desktop-style5-5.116.1-1-x86_64 +installed = qrcodegencpp-cmake-1.8.0-4.12-x86_64_v3 +installed = qrencode-4.1.1-4.9-x86_64_v3 +installed = qt5-3d-5.15.18-1-x86_64 +installed = qt5-base-5.15.18+kde+r109-2.1-x86_64_v3 +installed = qt5-charts-5.15.18-1-x86_64 +installed = qt5-connectivity-5.15.18+kde+r1-1-x86_64 +installed = qt5-declarative-5.15.18+kde+r23-1.1-x86_64_v3 +installed = qt5-graphicaleffects-5.15.18-1.1-x86_64_v3 +installed = qt5-imageformats-5.15.18+kde+r2-1.1-x86_64_v3 +installed = qt5-location-5.15.18+kde+r7-2.1-x86_64_v3 +installed = qt5-multimedia-5.15.18+kde+r2-1.1-x86_64_v3 +installed = qt5-networkauth-5.15.18-1.1-x86_64_v3 +installed = qt5-quick3d-5.15.18+kde+r1-1-x86_64 +installed = qt5-quickcontrols-5.15.18-1.1-x86_64_v3 +installed = qt5-quickcontrols2-5.15.18+kde+r5-1.1-x86_64_v3 +installed = qt5-remoteobjects-5.15.18-1-x86_64 +installed = qt5-script-5.15.19-3.1-x86_64_v3 +installed = qt5-scxml-5.15.18-1-x86_64 +installed = qt5-sensors-5.15.18-1.1-x86_64_v3 +installed = qt5-serialport-5.15.18-1.1-x86_64_v3 +installed = qt5-speech-5.15.18+kde+r1-1.1-x86_64_v3 +installed = qt5-svg-5.15.18+kde+r5-1.1-x86_64_v3 +installed = qt5-tools-5.15.18+kde+r3-1.1-x86_64_v3 +installed = qt5-translations-5.15.18-1-any +installed = qt5-virtualkeyboard-5.15.18-1.1-x86_64_v3 +installed = qt5-wayland-5.15.18+kde+r55-1.1-x86_64_v3 +installed = qt5-webchannel-5.15.18+kde+r3-1-x86_64 +installed = qt5-webengine-5.15.19-4-x86_64 +installed = qt5-websockets-5.15.18+kde+r2-1-x86_64 +installed = qt5-x11extras-5.15.18-1.1-x86_64_v3 +installed = qt5-xmlpatterns-5.15.18-1.1-x86_64_v3 +installed = qt5ct-kde-1.8-15-x86_64 +installed = qt6-5compat-6.10.2-1.1-x86_64_v3 +installed = qt6-base-6.10.2-1.1-x86_64_v3 +installed = qt6-charts-6.10.2-1.1-x86_64_v3 +installed = qt6-declarative-6.10.2-1.1-x86_64_v3 +installed = qt6-graphs-6.10.2-1.1-x86_64_v3 +installed = qt6-imageformats-6.10.2-1.1-x86_64_v3 +installed = qt6-location-6.10.2-1.1-x86_64_v3 +installed = qt6-multimedia-6.10.2-1.1-x86_64_v3 +installed = qt6-multimedia-ffmpeg-6.10.2-1.1-x86_64_v3 +installed = qt6-networkauth-6.10.2-1.1-x86_64_v3 +installed = qt6-positioning-6.10.2-1.1-x86_64_v3 +installed = qt6-quick3d-6.10.2-1.1-x86_64_v3 +installed = qt6-quicktimeline-6.10.2-1.1-x86_64_v3 +installed = qt6-scxml-6.10.2-1.1-x86_64_v3 +installed = qt6-sensors-6.10.2-1.1-x86_64_v3 +installed = qt6-serialport-6.10.2-1.1-x86_64_v3 +installed = qt6-shadertools-6.10.2-1.1-x86_64_v3 +installed = qt6-speech-6.10.2-1.1-x86_64_v3 +installed = qt6-svg-6.10.2-1.1-x86_64_v3 +installed = qt6-tools-6.10.2-1.1-x86_64_v3 +installed = qt6-translations-6.10.2-1-any +installed = qt6-virtualkeyboard-6.10.2-1.1-x86_64_v3 +installed = qt6-wayland-6.10.2-1.1-x86_64_v3 +installed = qt6-webchannel-6.10.2-1.1-x86_64_v3 +installed = qt6-webengine-6.10.2-1-x86_64 +installed = qt6-websockets-6.10.2-1.1-x86_64_v3 +installed = qt6ct-kde-0.11-5-x86_64 +installed = qt6pas-6.2.10-2.1-x86_64_v3 +installed = qtcreator-18.0.2-2-x86_64 +installed = qterminal-2.3.0-1.1-x86_64_v3 +installed = qtermwidget-2.3.0-2.1-x86_64_v3 +installed = qtkeychain-qt6-0.15.0-3-x86_64 +installed = quickshell-git-0.2.0.r70.gdacfa9d-2-x86_64 +installed = ragel-6.10-4.1-x86_64 +installed = range-v3-0.12.0-2-any +installed = raptor-2.0.16-9.1-x86_64_v3 +installed = rasqal-1:0.9.33-7.2-x86_64_v3 +installed = rav1e-0.8.1-2.1-x86_64_v3 +installed = rclone-1.73.1-1.1-x86_64_v3 +installed = rdma-core-61.0-1.1-x86_64_v3 +installed = re2-2:2025.11.05-1.1-x86_64_v3 +installed = readline-8.3.003-1.1-x86_64_v3 +installed = realtime-privileges-5-1-any +installed = redland-1:1.0.17-9.1-x86_64 +installed = resvg-0.47.0-2.1-x86_64_v3 +installed = rhash-1.4.6-1.1-x86_64_v3 +installed = ripgrep-15.1.0-2-x86_64_v3 +installed = ripgrep-all-0.10.10-1.1-x86_64_v3 +installed = rnnoise-1:0.2-1.1-x86_64 +installed = rofi-2.0.0-1.1-x86_64_v3 +installed = rose-pine-cursor-1.1.0-2-any +installed = rose-pine-hyprcursor-v0.3.2.r0.d2c0e680-1-any +installed = rpcbind-1.2.8-1.1-x86_64_v3 +installed = rpm-sequoia-1.10.1-1.1-x86_64_v3 +installed = rpm-tools-6.0.1-1.1-x86_64_v3 +installed = rsync-3.4.1-2.1-x86_64_v3 +installed = rsyslog-8.2510.0-2-x86_64 +installed = rt-tests-2.9-2.1-x86_64_v3 +installed = rtkit-0.14-1.1-x86_64_v3 +installed = rubberband-4.0.0-1.1-x86_64 +installed = run-parts-5.23.2-1.1-x86_64_v3 +installed = runc-1.4.0-1.1-x86_64_v3 +installed = runelite-1:2.7.5-1-any +installed = rust-1:1.93.1-1.1-x86_64_v3 +installed = rust-analyzer-20260202-1.1-x86_64_v3 +installed = rust-bindgen-0.72.1-1.1-x86_64_v3 +installed = rust-src-1:1.93.1-1.1-x86_64_v3 +installed = rutabaga-ffi-0.1.75-1.1-x86_64_v3 +installed = s2n-tls-1.7.0-1.1-x86_64_v3 +installed = samba-2:4.23.5-1.1-x86_64_v3 +installed = sbc-2.2-1.1-x86_64_v3 +installed = scdoc-1.11.4-1.1-x86_64_v3 +installed = scenefx0.4-0.4.1-2-x86_64 +installed = schedtool-1.3.0-8.1-x86_64_v3 +installed = scour-0.38.2-6-any +installed = screen-5.0.1-3.1-x86_64_v3 +installed = sdbus-cpp-2.2.1-1.1-x86_64_v3 +installed = sdl12-compat-1.2.68-2.1-x86_64 +installed = sdl2-compat-2.32.64-1.1-x86_64_v3 +installed = sdl2_image-2.8.8-1.1-x86_64_v3 +installed = sdl2_mixer-2.8.1-2.1-x86_64_v3 +installed = sdl2_net-1:2.2.0-2.1-x86_64 +installed = sdl2_ttf-2.24.0-2.1-x86_64_v3 +installed = sdl3-3.4.2-1.1-x86_64_v3 +installed = sdl3_ttf-3.2.2-3.2-x86_64_v3 +installed = sdl_image-1.2.12-9.1-x86_64 +installed = sdl_mixer-1.2.12-13.1-x86_64_v3 +installed = sdl_net-1.2.8-6.1-x86_64 +installed = sdl_sound-1.0.3-13.1-x86_64_v3 +installed = sdl_ttf-2.0.11-8.1-x86_64_v3 +installed = seabios-1.17.0-2-any +installed = seatd-0.9.2-1.1-x86_64_v3 +installed = sed-4.9-3.2-x86_64 +installed = semver-7.7.4-1-any +installed = serd-0.32.8-1.1-x86_64_v3 +installed = shaderc-2026.1-1.1-x86_64_v3 +installed = shadow-4.18.0-1.1-x86_64_v3 +installed = shared-mime-info-2.4-3.1-x86_64_v3 +installed = shfmt-3.12.0-1.1-x86_64_v3 +installed = showmethekey-1.19.0-1.1-x86_64_v3 +installed = signon-kwallet-extension-25.12.2-1.1-x86_64_v3 +installed = signon-plugin-oauth2-0.25-3-x86_64 +installed = signon-ui-0.17+20231016-3.1-x86_64 +installed = signond-8.61-3.1-x86_64 +installed = simde-0.8.2-1-any +installed = simdjson-1:4.3.1-1.1-x86_64_v3 +installed = slang-2.3.3-4.1-x86_64_v3 +installed = slurp-1.5.0-1.1-x86_64 +installed = smartmontools-7.5-1.1-x86_64_v3 +installed = smbclient-2:4.23.5-1.1-x86_64_v3 +installed = snappy-1.2.2-3.1-x86_64_v3 +installed = sndio-1.10.0-1.4-x86_64_v3 +installed = socat-1.8.1.1-1.1-x86_64_v3 +installed = sof-firmware-2025.12.2-1-x86_64 +installed = solaar-1.1.19-1-any +installed = solid-6.23.0-1.1-x86_64_v3 +installed = solid5-5.116.0-2.1-x86_64_v3 +installed = sonnet-6.23.0-1.1-x86_64_v3 +installed = sonnet5-5.116.0-2.1-x86_64_v3 +installed = sord-0.16.22-1.1-x86_64_v3 +installed = sound-theme-freedesktop-0.8-6-any +installed = soundtouch-2.4.0-1.1-x86_64_v3 +installed = spandsp-0.0.6-6-x86_64 +installed = spdlog-1.17.0-2.1-x86_64_v3 +installed = spectacle-1:6.6.0-1.1-x86_64_v3 +installed = speex-1.2.1-2.1-x86_64 +installed = speexdsp-1.2.1-2.1-x86_64 +installed = spice-0.16.0-2.1-x86_64_v3 +installed = spice-protocol-0.14.5-1-any +installed = spirv-headers-1:1.4.341.0-1-any +installed = spirv-tools-1:1.4.341.0-1.1-x86_64_v3 +installed = sqlite-3.51.2-2-x86_64_v3 +installed = sratom-0.6.22-1.1-x86_64_v3 +installed = srt-1.5.4-1.1-x86_64 +installed = starship-1.24.2-2-x86_64 +installed = startup-notification-0.12-9.1-x86_64_v3 +installed = steam-1.0.0.85-3.1-x86_64 +installed = steam-devices-1.0.0.85-3.1-x86_64 +installed = steam-native-runtime-1.0.0.75-8-x86_64 +installed = steamtinkerlaunch-git-12.12.r278.g8550ab2-1-any +installed = stk-5.0.1-3.2-x86_64_v3 +installed = stow-2.4.1-1-any +installed = strace-6.19-1.1-x86_64_v3 +installed = stylish-icon-theme-23.08-1-any +installed = stylua-2.3.1-2.1-x86_64_v3 +installed = sudo-1.9.17.p2-2.1-x86_64_v3 +installed = suitesparse-7.12.2-1.1-x86_64_v3 +installed = sunshine-2025.924.154138-3-x86_64 +installed = superfile-1.5.0-1.1-x86_64_v3 +installed = svt-av1-4.0.1-2-x86_64_v3 +installed = swappy-1.8.0-1.1-x86_64_v3 +installed = swayfx-0.5.3-4-x86_64 +installed = swig-4.4.0-2.1-x86_64_v3 +installed = swww-0.11.2-1.1-x86_64_v3 +installed = syndication-6.23.0-1.1-x86_64_v3 +installed = syntax-highlighting-6.23.0-1.1-x86_64_v3 +installed = sysfsutils-2.1.1-2.2-x86_64_v3 +installed = sysstat-12.7.9-1.1-x86_64_v3 +installed = systemd-259.1-1-x86_64 +installed = systemd-libs-259.1-1-x86_64 +installed = systemd-lsp-2026.01.17-1-x86_64 +installed = systemd-sysvcompat-259.1-1-x86_64 +installed = systemsettings-6.6.0-1.1-x86_64_v3 +installed = taglib-2.2-1.1-x86_64_v3 +installed = tailscale-1.94.2-1.1-x86_64_v3 +installed = talloc-2.4.4-1.1-x86_64_v3 +installed = tar-1.35-2.1-x86_64 +installed = tcl-8.6.16-1.1-x86_64 +installed = tdb-1.4.15-1.1-x86_64_v3 +installed = teamspeak-6.0.0beta3.4-1-x86_64 +installed = teamspeak3-3.6.2-5-x86_64 +installed = tela-circle-icon-theme-blue-2025_02_10-1-any +installed = tesseract-5.5.2-1.1-x86_64_v3 +installed = tesseract-data-afr-2:4.1.0-4-any +installed = tesseract-data-osd-2:4.1.0-4-any +installed = testdisk-7.2-2.1-x86_64 +installed = tevent-1:0.17.1-2.1-x86_64_v3 +installed = texinfo-7.2-1.1-x86_64_v3 +installed = texlab-5.25.1-1.1-x86_64_v3 +installed = thin-provisioning-tools-1.3.1-1.1-x86_64_v3 +installed = thunar-4.20.7-1.1-x86_64_v3 +installed = tinysparql-3.10.1-2-x86_64 +installed = tinyxml2-11.0.0-2-x86_64 +installed = tk-8.6.16-1.1-x86_64 +installed = tl-expected-1.3.1-1-any +installed = tldr-3.4.4-1-any +installed = tmon-6.19-2-x86_64 +installed = tmux-3.6_a-1.1-x86_64_v3 +installed = tmux-mem-cpu-load-3.8.0-1-x86_64 +installed = tomlplusplus-3.4.0-1.1-x86_64 +installed = tor-0.4.9.5-1.1-x86_64_v3 +installed = torbrowser-launcher-0.3.7-4-any +installed = torsocks-2.5.0-1.1-x86_64_v3 +installed = tpm2-tss-4.1.3-1.1-x86_64 +installed = tree-2.3.1-1-x86_64 +installed = tree-sitter-0.25.10-3.1-x86_64_v3 +installed = tree-sitter-c-0.24.1-1.1-x86_64_v3 +installed = tree-sitter-cli-git-0.26.5.r116.g5e23ccaac-1-x86_64 +installed = tree-sitter-lua-0.4.0-1.1-x86_64_v3 +installed = tree-sitter-markdown-0.5.1-1.1-x86_64_v3 +installed = tree-sitter-query-0.7.0-1.1-x86_64_v3 +installed = tree-sitter-vim-0.7.0-1.1-x86_64_v3 +installed = tree-sitter-vimdoc-4.0.0-1.1-x86_64_v3 +installed = tslib-1.24-1.1-x86_64_v3 +installed = ttf-0xproto-nerd-3.4.0-2-any +installed = ttf-cascadia-code-nerd-3.4.0-2-any +installed = ttf-fira-code-6.2-2-any +installed = ttf-fira-sans-1:4.301-2-any +installed = ttf-firacode-nerd-3.4.0-2-any +installed = ttf-hack-3.003-7-any +installed = ttf-jetbrains-mono-2.304-2-any +installed = ttf-jetbrains-mono-nerd-3.4.0-2-any +installed = ttf-liberation-2.1.5-2-any +installed = ttf-material-symbols-variable-git-4.0.0.r144.g310de998-1-any +installed = ttf-mononoki-nerd-3.4.0-2-any +installed = ttf-nerd-fonts-symbols-3.4.0-1-any +installed = ttf-nerd-fonts-symbols-common-3.4.0-1-any +installed = ttf-nerd-fonts-symbols-mono-3.4.0-1-any +installed = ttf-roboto-3.015-1-any +installed = ttf-rubik-vf-2.3.0-3-any +installed = ttf-segoe-ui-variable-1.0-1-any +installed = turbostat-6.19-2-x86_64 +installed = twolame-0.4.0-4.1-x86_64 +installed = typescript-5.9.3-2-any +installed = tzdata-2025c-1.1-x86_64_v3 +installed = uchardet-0.0.8-3.1-x86_64 +installed = udisks2-2.11.0-1.1-x86_64_v3 +installed = ufw-0.36.2-7-any +installed = umu-launcher-1.3.0-6-x86_64 +installed = uncrustify-0.82.0-1.1-x86_64_v3 +installed = unibilium-2.1.2-1.1-x86_64_v3 +installed = unrar-1:7.2.4-1.1-x86_64_v3 +installed = unzip-6.0-23.1-x86_64_v3 +installed = upower-1.91.1-1.1-x86_64_v3 +installed = usbip-6.19-2-x86_64 +installed = usbmuxd-1.1.1-4.1-x86_64 +installed = usbredir-0.15.0-1.1-x86_64_v3 +installed = usbutils-019-1.1-x86_64_v3 +installed = uthash-2.3.0-2-any +installed = util-linux-2.41.3-2.1-x86_64_v3 +installed = util-linux-libs-2.41.3-2.1-x86_64_v3 +installed = uv-0.10.4-1.1-x86_64_v3 +installed = uwsm-0.26.4-1-any +installed = v4l-utils-1.32.0-1.1-x86_64_v3 +installed = v4l2loopback-dkms-0.15.3-1-any +installed = vala-0.56.18-5.1-x86_64_v3 +installed = valgrind-3.25.1-4.1-x86_64_v3 +installed = vapoursynth-73-2.1-x86_64_v3 +installed = vde2-2.3.3-8.1-x86_64_v3 +installed = vdpauinfo-1.5-2.1-x86_64 +installed = verdict-1.4.4-1.1-x86_64_v3 +installed = vid.stab-1.1.1-2.1-x86_64 +installed = video-trimmer-25.03-2.1-x86_64_v3 +installed = vim-9.2.0038-1.1-x86_64_v3 +installed = vim-runtime-9.2.0038-1.1-x86_64_v3 +installed = virglrenderer-1.2.0-1.1-x86_64_v3 +installed = virtiofsd-1.13.3-1.1-x86_64_v3 +installed = virtualbox-7.2.6-1-x86_64 +installed = virtualbox-host-modules-arch-7.2.6-4.1-x86_64_v3 +installed = vkbasalt-cli-3.1.1-5-any +installed = vkmark-1:2025.01-2.1-x86_64_v3 +installed = vlc-3.0.21-32.1-x86_64_v3 +installed = vlc-cli-3.0.21-32.1-x86_64_v3 +installed = vlc-gui-qt-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-a52dec-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-alsa-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-archive-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-dav1d-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-dbus-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-dbus-screensaver-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-faad2-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-ffmpeg-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-flac-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-gnutls-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-inflate-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-journal-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-jpeg-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-lua-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-mpg123-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-ogg-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-opus-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-png-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-pulse-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-shout-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-speex-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-tag-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-theora-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-twolame-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-vorbis-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-vpx-3.0.21-32.1-x86_64_v3 +installed = vlc-plugin-xml-3.0.21-32.1-x86_64_v3 +installed = vlc-plugins-base-3.0.21-32.1-x86_64_v3 +installed = vlc-plugins-video-output-3.0.21-32.1-x86_64_v3 +installed = vmaf-3.0.0-2.1-x86_64_v3 +installed = volume_key-0.3.12-12.1-x86_64_v3 +installed = vte-common-0.82.3-1.1-x86_64_v3 +installed = vte3-0.82.3-1.1-x86_64_v3 +installed = vulkan-icd-loader-1.4.341.0-1.1-x86_64_v3 +installed = vulkan-tools-1.4.341.0-1.1-x86_64_v3 +installed = vulkan-validation-layers-1.4.341.0-1.1-x86_64_v3 +installed = wacomtablet-6.6.0-1.1-x86_64_v3 +installed = wallust-3.4.0-1-x86_64 +installed = wavpack-5.9.0-1.1-x86_64_v3 +installed = waybar-0.15.0-1.1-x86_64_v3 +installed = waydroid-1.6.1-1-any +installed = wayland-1.24.0-1.1-x86_64_v3 +installed = wayland-protocols-1.47-1-any +installed = wayland-utils-1.3.0-1.1-x86_64_v3 +installed = webkit2gtk-2.50.5-1-x86_64 +installed = webkit2gtk-4.1-2.50.5-1-x86_64 +installed = webp-pixbuf-loader-0.2.7-1.1-x86_64 +installed = webrtc-audio-processing-2.1-5.1-x86_64_v3 +installed = webrtc-audio-processing-1-1.3-5.1-x86_64_v3 +installed = websocketpp-0.8.2-4-any +installed = wev-1.1.0-1.1-x86_64_v3 +installed = wezterm-git-20240203.110809.r803.g05343b3-1-x86_64 +installed = wget-1.25.0-3.1-x86_64_v3 +installed = which-2.23-1.1-x86_64_v3 +installed = whois-5.6.6-1.1-x86_64_v3 +installed = wimlib-1.14.5-1.1-x86_64_v3 +installed = winboat-0.9.0-8-x86_64 +installed = wine-cachyos-2:10.0.20260207-1-x86_64 +installed = wine-cachyos-opt-2:10.0.20260207-1-x86_64 +installed = winetricks-20260125-1.1-x86_64_v3 +installed = wireless_tools-30.pre9-5.1-x86_64_v3 +installed = wireplumber-0.5.13-1.1-x86_64_v3 +installed = wireshark-cli-4.6.3-1-x86_64 +installed = wireshark-qt-4.6.3-1-x86_64 +installed = wl-clip-persist-0.5.0-1.1-x86_64_v3 +installed = wl-clipboard-1:2.2.1-3.1-x86_64_v3 +installed = wlogout-1.2.2-0-x86_64 +installed = wlr-protocols-r112.a741f0a-1-any +installed = wlr-randr-0.5.0-1.1-x86_64_v3 +installed = wlroots0.17-0.17.4-4.1-x86_64_v3 +installed = wlroots0.18-0.18.3-1.1-x86_64_v3 +installed = wlroots0.19-0.19.2-2.1-x86_64_v3 +installed = wlsunset-0.4.0-1.1-x86_64 +installed = woeusb-5.2.4-1-any +installed = woff2-1.0.2-6.1-x86_64_v3 +installed = wofi-1.5.3-1.1-x86_64_v3 +installed = wolfssl-5.8.4-1-x86_64 +installed = wpa_supplicant-2:2.11-5.1-x86_64_v3 +installed = wscat-6.1.0-1-x86_64 +installed = wxwidgets-common-3.2.9-4-x86_64 +installed = wxwidgets-gtk3-3.2.9-4-x86_64 +installed = x264-3:0.165.r3222.b35605a-2.1-x86_64_v3 +installed = x265-4.1-1.1-x86_64_v3 +installed = x86_energy_perf_policy-6.19-2-x86_64 +installed = xapian-core-1:1.4.29-1.1-x86_64_v3 +installed = xcb-imdkit-1.0.9-1.1-x86_64 +installed = xcb-proto-1.17.0-4-any +installed = xcb-util-0.4.1-2.2-x86_64_v3 +installed = xcb-util-cursor-0.1.6-1.1-x86_64_v3 +installed = xcb-util-errors-1.0.1-2.1-x86_64 +installed = xcb-util-image-0.4.1-3.1-x86_64 +installed = xcb-util-keysyms-0.4.1-5.1-x86_64 +installed = xcb-util-renderutil-0.3.10-2.1-x86_64 +installed = xcb-util-wm-0.4.2-2.1-x86_64 +installed = xclip-0.13-6.1-x86_64 +installed = xcur2png-0.7.1-8.1-x86_64 +installed = xdg-dbus-proxy-0.1.6-1.1-x86_64 +installed = xdg-desktop-portal-1.20.3-2.1-x86_64_v3 +installed = xdg-desktop-portal-gtk-1.15.3-1.1-x86_64_v3 +installed = xdg-desktop-portal-hyprland-1.3.11-3.1-x86_64_v3 +installed = xdg-desktop-portal-kde-6.6.0-1.1-x86_64_v3 +installed = xdg-user-dirs-0.19-2.1-x86_64_v3 +installed = xdg-utils-1.2.1-2-any +installed = xdotool-4.20251130.1-1.1-x86_64_v3 +installed = xerces-c-3.3.0-3.1-x86_64_v3 +installed = xf86-input-libinput-1.5.0-1.1-x86_64 +installed = xf86-input-wacom-1.2.4-1.1-x86_64_v3 +installed = xf86-video-amdgpu-25.0.0-1.1-x86_64_v3 +installed = xfconf-4.20.0-2.1-x86_64 +installed = xfsprogs-6.18.0-1.1-x86_64_v3 +installed = xkeyboard-config-2.46-1-any +installed = xmlsec-1.3.9-1.1-x86_64_v3 +installed = xone-dkms-0.5.5-1-x86_64 +installed = xone-dongle-firmware-2.0.0-1-any +installed = xorg-fonts-encodings-1.1.0-1-any +installed = xorg-server-21.1.21-1.1-x86_64_v3 +installed = xorg-server-common-21.1.21-1.1-x86_64_v3 +installed = xorg-server-xvfb-21.1.21-1.1-x86_64_v3 +installed = xorg-setxkbmap-1.3.4-2.1-x86_64 +installed = xorg-xauth-1.1.5-1.1-x86_64_v3 +installed = xorg-xdpyinfo-1.4.0-1.1-x86_64_v3 +installed = xorg-xhost-1.0.10-1.2-x86_64_v3 +installed = xorg-xinit-1.4.4-1.1-x86_64_v3 +installed = xorg-xinput-1.6.4-2.1-x86_64 +installed = xorg-xkbcomp-1.5.0-1.1-x86_64_v3 +installed = xorg-xmessage-1.0.7-1.1-x86_64 +installed = xorg-xmodmap-1.0.11-2.1-x86_64 +installed = xorg-xprop-1.2.8-1.1-x86_64 +installed = xorg-xrandr-1.5.3-1.1-x86_64 +installed = xorg-xrdb-1.2.2-2.1-x86_64 +installed = xorg-xwayland-24.1.9-1.1-x86_64_v3 +installed = xorg-xwininfo-1.1.6-2.1-x86_64 +installed = xorgproto-2025.1-1-any +installed = xremap-hypr-bin-0.14.15-1-x86_64 +installed = xsel-1.2.1-2.1-x86_64 +installed = xsettingsd-1.0.2-3.1-x86_64_v3 +installed = xvidcore-1.3.7-3.1-x86_64 +installed = xxhash-0.8.3-1-x86_64 +installed = xz-5.8.2-2-x86_64_v3 +installed = yabsnap-2.3.4-1-any +installed = yad-14.2-1.1-x86_64_v3 +installed = yajl-2.1.0-6.1-x86_64 +installed = yaml-cpp-0.8.0-3.1-x86_64_v3 +installed = yara-4.5.5-1.1-x86_64_v3 +installed = yarn-1.22.22-2-any +installed = yasm-1.3.0-9.1-x86_64_v3 +installed = yay-12.5.7-1-x86_64 +installed = yay-debug-12.5.7-1-x86_64 +installed = yazi-26.1.22-2.1-x86_64_v3 +installed = ydotool-1.0.4-2.1-x86_64 +installed = yelp-tools-42.1-2-any +installed = yelp-xsl-49.0-1-any +installed = yt-dlp-2026.02.21-1-any +installed = yt-dlp-ejs-0.5.0-1-any +installed = yyjson-0.12.0-1.1-x86_64_v3 +installed = zathura-2026.02.09-1.1-x86_64_v3 +installed = zathura-pdf-mupdf-2026.02.03-4.1-x86_64_v3 +installed = zed-0.224.11-1.1-x86_64_v3 +installed = zellij-0.43.1-2.1-x86_64_v3 +installed = zen-browser-bin-1.18.10b-1-x86_64 +installed = zenity-4.2.1-1.1-x86_64_v3 +installed = zeromq-4.3.5-3.1-x86_64_v3 +installed = zig-0.15.2-2.1-x86_64_v3 +installed = zimg-3.0.6-1.1-x86_64_v3 +installed = zint-2.16.0-1.1-x86_64_v3 +installed = zip-3.0-11.1-x86_64 +installed = zita-convolver-4.0.3-5.1-x86_64_v3 +installed = zix-0.8.0-1.1-x86_64_v3 +installed = zlib-ng-2.3.3-2-x86_64_v3 +installed = zlib-ng-compat-2.3.3-2-x86_64_v3 +installed = zmx-git-r211.7a30c62-1-x86_64 +installed = zoxide-0.9.9-2.1-x86_64_v3 +installed = zram-generator-1.2.1-1.1-x86_64 +installed = zsh-5.9-5.1-x86_64 +installed = zsh-autosuggestions-0.7.1-1-any +installed = zsh-completions-0.35.0-3-any +installed = zsh-fast-syntax-highlighting-1.56-1-any +installed = zsh-syntax-highlighting-0.8.0-1-any +installed = zshell-0.1.0-1-any +installed = zstd-1.5.7-2-x86_64 +installed = zterm-0.1.0-1-x86_64 +installed = zxing-cpp-3.0.2-1.1-x86_64_v3 +installed = zziplib-0.13.80-1.1-x86_64_v3 diff --git a/pkg/zshell/.MTREE b/pkg/zshell/.MTREE new file mode 100644 index 0000000..7d24a1f Binary files /dev/null and b/pkg/zshell/.MTREE differ diff --git a/pkg/zshell/.PKGINFO b/pkg/zshell/.PKGINFO new file mode 100644 index 0000000..f3c9541 --- /dev/null +++ b/pkg/zshell/.PKGINFO @@ -0,0 +1,28 @@ +# Generated by makepkg 7.1.0 +# using fakeroot version 1.37.2 +pkgname = zshell +pkgbase = zshell +xdata = pkgtype=pkg +pkgver = 0.1.0-1 +pkgdesc = The cli for zshell +url = https://github.com/Zacharias-Brohn/z-bar-qt +builddate = 1771871772 +packager = Unknown Packager +size = 1533615 +arch = any +license = GPL-3.0-only +depend = python +depend = python-pillow +depend = python-materialyoucolor +depend = libnotify +depend = swappy +depend = dart-sass +depend = app2unit +depend = wl-clipboard +depend = dconf +depend = cliphist +depend = python-typer +makedepend = python-build +makedepend = python-installer +makedepend = python-hatch +makedepend = python-hatch-vcs diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/Anim.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Anim.qml new file mode 100644 index 0000000..c32e713 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Anim.qml @@ -0,0 +1,9 @@ +import QtQuick +import qs.Modules +import qs.Config + +NumberAnimation { + duration: MaterialEasing.standardTime + easing.type: Easing.BezierSpline + easing.bezierCurve: MaterialEasing.standard +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CAnim.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CAnim.qml new file mode 100644 index 0000000..09b33b1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CAnim.qml @@ -0,0 +1,9 @@ +import QtQuick +import qs.Modules +import qs.Config + +ColorAnimation { + duration: MaterialEasing.standardTime + easing.type: Easing.BezierSpline + easing.bezierCurve: MaterialEasing.standard +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CircularIndicator.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CircularIndicator.qml new file mode 100644 index 0000000..c398d48 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CircularIndicator.qml @@ -0,0 +1,108 @@ +import qs.Helpers +import qs.Config +import qs.Modules +import ZShell.Internal +import QtQuick +import QtQuick.Templates + +BusyIndicator { + id: root + + enum AnimType { + Advance = 0, + Retreat + } + + enum AnimState { + Stopped, + Running, + Completing + } + + property real implicitSize: Appearance.font.size.normal * 3 + property real strokeWidth: Appearance.padding.small * 0.8 + property color fgColour: DynamicColors.palette.m3primary + property color bgColour: DynamicColors.palette.m3secondaryContainer + + property alias type: manager.indeterminateAnimationType + readonly property alias progress: manager.progress + + property real internalStrokeWidth: strokeWidth + property int animState + + padding: 0 + implicitWidth: implicitSize + implicitHeight: implicitSize + + Component.onCompleted: { + if (running) { + running = false; + running = true; + } + } + + onRunningChanged: { + if (running) { + manager.completeEndProgress = 0; + animState = CircularIndicator.Running; + } else { + if (animState == CircularIndicator.Running) + animState = CircularIndicator.Completing; + } + } + + states: State { + name: "stopped" + when: !root.running + + PropertyChanges { + root.opacity: 0 + root.internalStrokeWidth: root.strokeWidth / 3 + } + } + + transitions: Transition { + Anim { + properties: "opacity,internalStrokeWidth" + duration: manager.completeEndDuration * Appearance.anim.durations.scale + } + } + + contentItem: CircularProgress { + anchors.fill: parent + strokeWidth: root.internalStrokeWidth + fgColour: root.fgColour + bgColour: root.bgColour + padding: root.padding + rotation: manager.rotation + startAngle: manager.startFraction * 360 + value: manager.endFraction - manager.startFraction + } + + CircularIndicatorManager { + id: manager + } + + NumberAnimation { + running: root.animState !== CircularIndicator.Stopped + loops: Animation.Infinite + target: manager + property: "progress" + from: 0 + to: 1 + duration: manager.duration * Appearance.anim.durations.scale + } + + NumberAnimation { + running: root.animState === CircularIndicator.Completing + target: manager + property: "completeEndProgress" + from: 0 + to: 1 + duration: manager.completeEndDuration * Appearance.anim.durations.scale + onFinished: { + if (root.animState === CircularIndicator.Completing) + root.animState = CircularIndicator.Stopped; + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CircularProgress.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CircularProgress.qml new file mode 100644 index 0000000..ef98fd6 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CircularProgress.qml @@ -0,0 +1,69 @@ +import QtQuick +import QtQuick.Shapes +import qs.Helpers +import qs.Config +import qs.Modules + +Shape { + id: root + + property real value + property int startAngle: -90 + property int strokeWidth: Appearance.padding.smaller + property int padding: 0 + property int spacing: Appearance.spacing.small + property color fgColour: DynamicColors.palette.m3primary + property color bgColour: DynamicColors.palette.m3secondaryContainer + + readonly property real size: Math.min(width, height) + readonly property real arcRadius: (size - padding - strokeWidth) / 2 + readonly property real vValue: value || 1 / 360 + readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI) + + preferredRendererType: Shape.CurveRenderer + asynchronous: true + + ShapePath { + fillColor: "transparent" + strokeColor: root.bgColour + strokeWidth: root.strokeWidth + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + startAngle: root.startAngle + 360 * root.vValue + root.gapAngle + sweepAngle: Math.max(-root.gapAngle, 360 * (1 - root.vValue) - root.gapAngle * 2) + radiusX: root.arcRadius + radiusY: root.arcRadius + centerX: root.size / 2 + centerY: root.size / 2 + } + + Behavior on strokeColor { + CAnim { + duration: Appearance.anim.durations.large + } + } + } + + ShapePath { + fillColor: "transparent" + strokeColor: root.fgColour + strokeWidth: root.strokeWidth + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + startAngle: root.startAngle + sweepAngle: 360 * root.vValue + radiusX: root.arcRadius + radiusY: root.arcRadius + centerX: root.size / 2 + centerY: root.size / 2 + } + + Behavior on strokeColor { + CAnim { + duration: Appearance.anim.durations.large + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/ColoredIcon.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/ColoredIcon.qml new file mode 100644 index 0000000..fb38a08 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/ColoredIcon.qml @@ -0,0 +1,35 @@ +pragma ComponentBehavior: Bound + +import ZShell +import Quickshell.Widgets +import QtQuick + +IconImage { + id: root + + required property color color + + asynchronous: true + + layer.enabled: true + layer.effect: Coloriser { + sourceColor: analyser.dominantColour + colorizationColor: root.color + } + + layer.onEnabledChanged: { + if (layer.enabled && status === Image.Ready) + analyser.requestUpdate(); + } + + onStatusChanged: { + if (layer.enabled && status === Image.Ready) + analyser.requestUpdate(); + } + + ImageAnalyser { + id: analyser + + sourceItem: root + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/Coloriser.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Coloriser.qml new file mode 100644 index 0000000..f0212f1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Coloriser.qml @@ -0,0 +1,14 @@ +import QtQuick +import QtQuick.Effects +import qs.Modules + +MultiEffect { + property color sourceColor: "black" + + colorization: 1 + brightness: 1 - sourceColor.hslLightness + + Behavior on colorizationColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomAudioSlider.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomAudioSlider.qml new file mode 100644 index 0000000..8a74a29 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomAudioSlider.qml @@ -0,0 +1,83 @@ +import QtQuick +import QtQuick.Templates +import qs.Config +import qs.Modules + +Slider { + id: root + + required property real peak + property color nonPeakColor: DynamicColors.tPalette.m3primary + property color peakColor: DynamicColors.palette.m3primary + + background: Item { + CustomRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.topMargin: root.implicitHeight / 3 + anchors.bottomMargin: root.implicitHeight / 3 + + implicitWidth: root.handle.x - root.implicitHeight + + color: root.nonPeakColor + radius: 1000 + topRightRadius: root.implicitHeight / 15 + bottomRightRadius: root.implicitHeight / 15 + + CustomRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + + implicitWidth: parent.width * root.peak + radius: 1000 + topRightRadius: root.implicitHeight / 15 + bottomRightRadius: root.implicitHeight / 15 + + color: root.peakColor + + Behavior on implicitWidth { + Anim { duration: 50 } + } + } + } + + CustomRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.topMargin: root.implicitHeight / 3 + anchors.bottomMargin: root.implicitHeight / 3 + + implicitWidth: root.implicitWidth - root.handle.x - root.handle.implicitWidth - root.implicitHeight + + Component.onCompleted: { + console.log(root.handle.x, implicitWidth) + } + + + color: DynamicColors.tPalette.m3surfaceContainer + radius: 1000 + topLeftRadius: root.implicitHeight / 15 + bottomLeftRadius: root.implicitHeight / 15 + } + } + + handle: CustomRect { + x: root.visualPosition * root.availableWidth - implicitWidth / 2 + + implicitWidth: 5 + implicitHeight: 15 + anchors.verticalCenter: parent.verticalCenter + + color: DynamicColors.palette.m3primary + radius: 1000 + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomBusyIndicator.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomBusyIndicator.qml new file mode 100644 index 0000000..223989e --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomBusyIndicator.qml @@ -0,0 +1,65 @@ +import QtQuick +import QtQuick.Controls.Basic + +BusyIndicator { + id: control + property color color: delegate.color + property int busySize: 64 + + contentItem: Item { + implicitWidth: control.busySize + implicitHeight: control.busySize + + Item { + id: item + x: parent.width / 2 - (control.busySize / 2) + y: parent.height / 2 - (control.busySize / 2) + width: control.busySize + height: control.busySize + opacity: control.running ? 1 : 0 + + Behavior on opacity { + OpacityAnimator { + duration: 250 + } + } + + RotationAnimator { + target: item + running: control.visible && control.running + from: 0 + to: 360 + loops: Animation.Infinite + duration: 1250 + } + + Repeater { + id: repeater + model: 6 + + CustomRect { + id: delegate + x: item.width / 2 - width / 2 + y: item.height / 2 - height / 2 + implicitWidth: 10 + implicitHeight: 10 + radius: 5 + color: control.color + + required property int index + + transform: [ + Translate { + y: -Math.min(item.width, item.height) * 0.5 + 5 + }, + Rotation { + angle: delegate.index / repeater.count * 360 + origin.x: 5 + origin.y: 5 + } + ] + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomButton.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomButton.qml new file mode 100644 index 0000000..62586bc --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomButton.qml @@ -0,0 +1,33 @@ +import QtQuick +import QtQuick.Controls + +Button { + id: control + + required property color textColor + required property color bgColor + property int radius: 4 + + contentItem: CustomText { + text: control.text + + opacity: control.enabled ? 1.0 : 0.5 + color: control.textColor + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + background: CustomRect { + opacity: control.enabled ? 1.0 : 0.5 + + radius: control.radius + color: control.bgColor + } + + StateLayer { + radius: control.radius + function onClicked(): void { + control.clicked(); + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomCheckbox.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomCheckbox.qml new file mode 100644 index 0000000..2749781 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomCheckbox.qml @@ -0,0 +1,39 @@ +import QtQuick +import QtQuick.Controls +import qs.Config + +CheckBox { + id: control + + property int checkWidth: 20 + property int checkHeight: 20 + + indicator: CustomRect { + implicitWidth: control.checkWidth + implicitHeight: control.checkHeight + // x: control.leftPadding + // y: parent.implicitHeight / 2 - implicitHeight / 2 + border.color: control.checked ? DynamicColors.palette.m3primary : "transparent" + color: DynamicColors.palette.m3surfaceVariant + + radius: 4 + + CustomRect { + implicitWidth: control.checkWidth - (x * 2) + implicitHeight: control.checkHeight - (y * 2) + x: 4 + y: 4 + radius: 3 + color: DynamicColors.palette.m3primary + visible: control.checked + } + } + + contentItem: CustomText { + text: control.text + font.pointSize: control.font.pointSize + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: control.checkWidth + control.leftPadding + 8 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomClippingRect.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomClippingRect.qml new file mode 100644 index 0000000..120b117 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomClippingRect.qml @@ -0,0 +1,13 @@ +import Quickshell.Widgets +import QtQuick +import qs.Modules + +ClippingRectangle { + id: root + + color: "transparent" + + Behavior on color { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomFlickable.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomFlickable.qml new file mode 100644 index 0000000..05ba9a8 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomFlickable.qml @@ -0,0 +1,14 @@ +import QtQuick +import qs.Modules + +Flickable { + id: root + + maximumFlickVelocity: 3000 + + rebound: Transition { + Anim { + properties: "x,y" + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomIcon.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomIcon.qml new file mode 100644 index 0000000..930c852 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomIcon.qml @@ -0,0 +1,10 @@ +pragma ComponentBehavior: Bound + +import Quickshell.Widgets +import QtQuick + +IconImage { + id: root + + asynchronous: true +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomListView.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomListView.qml new file mode 100644 index 0000000..e570513 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomListView.qml @@ -0,0 +1,15 @@ +import QtQuick +import qs.Config +import qs.Modules + +ListView { + id: root + + maximumFlickVelocity: 3000 + + rebound: Transition { + Anim { + properties: "x,y" + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomMouseArea.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomMouseArea.qml new file mode 100644 index 0000000..a17a74e --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomMouseArea.qml @@ -0,0 +1,19 @@ +import QtQuick + +MouseArea { + property int scrollAccumulatedY: 0 + + function onWheel(event: WheelEvent): void { + } + + onWheel: event => { + if (Math.sign(event.angleDelta.y) !== Math.sign(scrollAccumulatedY)) + scrollAccumulatedY = 0; + scrollAccumulatedY += event.angleDelta.y; + + if (Math.abs(scrollAccumulatedY) >= 120) { + onWheel(event); + scrollAccumulatedY = 0; + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomRadioButton.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomRadioButton.qml new file mode 100644 index 0000000..cfaa64c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomRadioButton.qml @@ -0,0 +1,56 @@ +import QtQuick +import QtQuick.Templates +import qs.Config +import qs.Modules + +RadioButton { + id: root + + font.pointSize: 12 + + implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin + implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight) + + indicator: Rectangle { + id: outerCircle + + implicitWidth: 16 + implicitHeight: 16 + radius: 1000 + color: "transparent" + border.color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant + border.width: 2 + anchors.verticalCenter: parent.verticalCenter + + StateLayer { + anchors.margins: -7 + color: root.checked ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3primary + z: -1 + + function onClicked(): void { + root.click(); + } + } + + CustomRect { + anchors.centerIn: parent + implicitWidth: 8 + implicitHeight: 8 + + radius: 1000 + color: Qt.alpha(DynamicColors.palette.m3primary, root.checked ? 1 : 0) + } + + Behavior on border.color { + CAnim {} + } + } + + contentItem: CustomText { + text: root.text + font.pointSize: root.font.pointSize + anchors.verticalCenter: parent.verticalCenter + anchors.left: outerCircle.right + anchors.leftMargin: 10 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomRect.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomRect.qml new file mode 100644 index 0000000..0aba620 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomRect.qml @@ -0,0 +1,12 @@ +import QtQuick +import qs.Modules + +Rectangle { + id: root + + color: "transparent" + + Behavior on color { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomScrollBar.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomScrollBar.qml new file mode 100644 index 0000000..d57cc43 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomScrollBar.qml @@ -0,0 +1,189 @@ +import qs.Config +import qs.Modules +import QtQuick +import QtQuick.Templates + +ScrollBar { + id: root + + required property Flickable flickable + property bool shouldBeActive + property real nonAnimPosition + property bool animating + + onHoveredChanged: { + if (hovered) + shouldBeActive = true; + else + shouldBeActive = flickable.moving; + } + + property bool _updatingFromFlickable: false + property bool _updatingFromUser: false + + // Sync nonAnimPosition with Qt's automatic position binding + onPositionChanged: { + if (_updatingFromUser) { + _updatingFromUser = false; + return; + } + if (position === nonAnimPosition) { + animating = false; + return; + } + if (!animating && !_updatingFromFlickable && !fullMouse.pressed) { + nonAnimPosition = position; + } + } + + // Sync nonAnimPosition with flickable when not animating + Connections { + target: flickable + function onContentYChanged() { + if (!animating && !fullMouse.pressed) { + _updatingFromFlickable = true; + const contentHeight = flickable.contentHeight; + const height = flickable.height; + if (contentHeight > height) { + nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); + } else { + nonAnimPosition = 0; + } + _updatingFromFlickable = false; + } + } + } + + Component.onCompleted: { + if (flickable) { + const contentHeight = flickable.contentHeight; + const height = flickable.height; + if (contentHeight > height) { + nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); + } + } + } + implicitWidth: 8 + + contentItem: CustomRect { + anchors.left: parent.left + anchors.right: parent.right + opacity: { + if (root.size === 1) + return 0; + if (fullMouse.pressed) + return 1; + if (mouse.containsMouse) + return 0.8; + if (root.policy === ScrollBar.AlwaysOn || root.shouldBeActive) + return 0.6; + return 0; + } + radius: 1000 + color: DynamicColors.palette.m3secondary + + MouseArea { + id: mouse + + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + + Behavior on opacity { + Anim {} + } + } + + Connections { + target: root.flickable + + function onMovingChanged(): void { + if (root.flickable.moving) + root.shouldBeActive = true; + else + hideDelay.restart(); + } + } + + Timer { + id: hideDelay + + interval: 600 + onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered + } + + CustomMouseArea { + id: fullMouse + + anchors.fill: parent + preventStealing: true + + onPressed: event => { + root.animating = true; + root._updatingFromUser = true; + const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2)); + root.nonAnimPosition = newPos; + // Update flickable position + // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] + if (root.flickable) { + const contentHeight = root.flickable.contentHeight; + const height = root.flickable.height; + if (contentHeight > height) { + const maxContentY = contentHeight - height; + const maxPos = 1 - root.size; + const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; + root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); + } + } + } + + onPositionChanged: event => { + root._updatingFromUser = true; + const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2)); + root.nonAnimPosition = newPos; + // Update flickable position + // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] + if (root.flickable) { + const contentHeight = root.flickable.contentHeight; + const height = root.flickable.height; + if (contentHeight > height) { + const maxContentY = contentHeight - height; + const maxPos = 1 - root.size; + const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; + root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); + } + } + } + + function onWheel(event: WheelEvent): void { + root.animating = true; + root._updatingFromUser = true; + let newPos = root.nonAnimPosition; + if (event.angleDelta.y > 0) + newPos = Math.max(0, root.nonAnimPosition - 0.1); + else if (event.angleDelta.y < 0) + newPos = Math.min(1 - root.size, root.nonAnimPosition + 0.1); + root.nonAnimPosition = newPos; + // Update flickable position + // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] + if (root.flickable) { + const contentHeight = root.flickable.contentHeight; + const height = root.flickable.height; + if (contentHeight > height) { + const maxContentY = contentHeight - height; + const maxPos = 1 - root.size; + const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; + root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); + } + } + } + } + + Behavior on position { + enabled: !fullMouse.pressed + + Anim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomShortcut.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomShortcut.qml new file mode 100644 index 0000000..c60cbef --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomShortcut.qml @@ -0,0 +1,5 @@ +import Quickshell.Hyprland + +GlobalShortcut { + appid: "zshell" +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomSlider.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomSlider.qml new file mode 100644 index 0000000..5f21e71 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomSlider.qml @@ -0,0 +1,53 @@ +import QtQuick +import QtQuick.Templates +import qs.Config +import qs.Modules + +Slider { + id: root + + background: Item { + CustomRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + + implicitWidth: root.handle.x - root.implicitHeight / 2 + + color: DynamicColors.palette.m3primary + radius: 1000 + topRightRadius: root.implicitHeight / 6 + bottomRightRadius: root.implicitHeight / 6 + } + + CustomRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 2 + + color: DynamicColors.tPalette.m3surfaceContainer + radius: 1000 + topLeftRadius: root.implicitHeight / 6 + bottomLeftRadius: root.implicitHeight / 6 + } + } + + handle: CustomRect { + x: root.visualPosition * root.availableWidth - implicitWidth / 2 + + implicitWidth: 5 + implicitHeight: 15 + anchors.verticalCenter: parent.verticalCenter + + color: DynamicColors.palette.m3primary + radius: 1000 + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomSwitch.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomSwitch.qml new file mode 100644 index 0000000..83de2dd --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomSwitch.qml @@ -0,0 +1,66 @@ +import qs.Config +import qs.Modules +import QtQuick +import QtQuick.Templates +import QtQuick.Shapes + +Switch { + id: root + + property int cLayer: 1 + + implicitWidth: implicitIndicatorWidth + implicitHeight: implicitIndicatorHeight + + indicator: CustomRect { + radius: 1000 + color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) + + implicitWidth: implicitHeight * 1.7 + implicitHeight: 13 + 7 * 2 + + CustomRect { + readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.3 : implicitHeight + + radius: 1000 + color: root.checked ? DynamicColors.palette.m3onPrimary : DynamicColors.layer(DynamicColors.palette.m3outline, root.cLayer + 1) + + x: root.checked ? parent.implicitWidth - nonAnimWidth - 10 / 2 : 10 / 2 + implicitWidth: nonAnimWidth + implicitHeight: parent.implicitHeight - 10 + anchors.verticalCenter: parent.verticalCenter + + CustomRect { + anchors.fill: parent + radius: parent.radius + + color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface + opacity: root.pressed ? 0.1 : root.hovered ? 0.08 : 0 + + Behavior on opacity { + Anim {} + } + } + + Behavior on x { + Anim {} + } + + Behavior on implicitWidth { + Anim {} + } + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + enabled: false + } + + component PropAnim: PropertyAnimation { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + easing.type: Easing.BezierSpline + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomText.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomText.qml new file mode 100644 index 0000000..4b30529 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomText.qml @@ -0,0 +1,49 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import qs.Config +import qs.Modules + +Text { + id: root + + property bool animate: false + property string animateProp: "scale" + property real animateFrom: 0 + property real animateTo: 1 + property int animateDuration: 400 + + renderType: Text.NativeRendering + textFormat: Text.PlainText + color: DynamicColors.palette.m3onSurface + font.family: Appearance.font.family.sans + font.pointSize: 12 + + Behavior on color { + CAnim {} + } + + Behavior on text { + enabled: root.animate + + SequentialAnimation { + Anim { + to: root.animateFrom + easing.bezierCurve: MaterialEasing.standardAccel + } + PropertyAction {} + Anim { + to: root.animateTo + easing.bezierCurve: MaterialEasing.standardDecel + } + } + } + + component Anim: NumberAnimation { + target: root + property: root.animateProp.split(",").length === 1 ? root.animateProp : "" + properties: root.animateProp.split(",").length > 1 ? root.animateProp : "" + duration: root.animateDuration / 2 + easing.type: Easing.BezierSpline + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTextField.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTextField.qml new file mode 100644 index 0000000..b739901 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTextField.qml @@ -0,0 +1,76 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import qs.Helpers +import qs.Config +import qs.Modules + +TextField { + id: root + + color: DynamicColors.palette.m3onSurface + placeholderTextColor: DynamicColors.palette.m3outline + font.family: Appearance.font.family.sans + font.pointSize: Appearance.font.size.smaller + renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering + cursorVisible: !readOnly + + background: null + + cursorDelegate: CustomRect { + id: cursor + + property bool disableBlink + + implicitWidth: 2 + color: DynamicColors.palette.m3primary + radius: Appearance.rounding.normal + + Connections { + target: root + + function onCursorPositionChanged(): void { + if (root.activeFocus && root.cursorVisible) { + cursor.opacity = 1; + cursor.disableBlink = true; + enableBlink.restart(); + } + } + } + + Timer { + id: enableBlink + + interval: 100 + onTriggered: cursor.disableBlink = false + } + + Timer { + running: root.activeFocus && root.cursorVisible && !cursor.disableBlink + repeat: true + triggeredOnStart: true + interval: 500 + onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1 + } + + Binding { + when: !root.activeFocus || !root.cursorVisible + cursor.opacity: 0 + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + } + } + } + + Behavior on color { + CAnim {} + } + + Behavior on placeholderTextColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTooltip.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTooltip.qml new file mode 100644 index 0000000..2211849 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTooltip.qml @@ -0,0 +1,23 @@ +import QtQuick +import QtQuick.Controls +import qs.Components + +ToolTip { + id: root + property bool extraVisibleCondition: true + property bool alternativeVisibleCondition: false + readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition + verticalPadding: 5 + horizontalPadding: 10 + background: null + + visible: internalVisibleCondition + + contentItem: CustomTooltipContent { + id: contentItem + text: root.text + shown: root.internalVisibleCondition + horizontalPadding: root.horizontalPadding + verticalPadding: root.verticalPadding + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTooltipContent.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTooltipContent.qml new file mode 100644 index 0000000..6a399cb --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/CustomTooltipContent.qml @@ -0,0 +1,48 @@ +import QtQuick +import qs.Components +import qs.Modules +import qs.Config + +Item { + id: root + required property string text + property bool shown: false + property real horizontalPadding: 10 + property real verticalPadding: 5 + implicitWidth: tooltipTextObject.implicitWidth + 2 * root.horizontalPadding + implicitHeight: tooltipTextObject.implicitHeight + 2 * root.verticalPadding + + property bool isVisible: backgroundRectangle.implicitHeight > 0 + + Rectangle { + id: backgroundRectangle + anchors { + bottom: root.bottom + horizontalCenter: root.horizontalCenter + } + color: DynamicColors.tPalette.m3inverseSurface ?? "#3C4043" + radius: 8 + opacity: shown ? 1 : 0 + implicitWidth: shown ? (tooltipTextObject.implicitWidth + 2 * root.horizontalPadding) : 0 + implicitHeight: shown ? (tooltipTextObject.implicitHeight + 2 * root.verticalPadding) : 0 + clip: true + + Behavior on implicitWidth { + Anim {} + } + Behavior on implicitHeight { + Anim {} + } + Behavior on opacity { + Anim {} + } + + CustomText { + id: tooltipTextObject + anchors.centerIn: parent + text: root.text + color: DynamicColors.palette.m3inverseOnSurface ?? "#FFFFFF" + wrapMode: Text.Wrap + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/Elevation.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Elevation.qml new file mode 100644 index 0000000..83f9639 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Elevation.qml @@ -0,0 +1,18 @@ +import qs.Config +import qs.Modules +import QtQuick +import QtQuick.Effects + +RectangularShadow { + property int level + property real dp: [0, 1, 3, 6, 8, 12][level] + + color: Qt.alpha(DynamicColors.palette.m3shadow, 0.7) + blur: (dp * 5) ** 0.7 + spread: -dp * 0.3 + (dp * 0.1) ** 2 + offset.y: dp / 2 + + Behavior on dp { + Anim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/ExtraIndicator.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/ExtraIndicator.qml new file mode 100644 index 0000000..e67c284 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/ExtraIndicator.qml @@ -0,0 +1,49 @@ +import qs.Config +import qs.Modules +import QtQuick + +CustomRect { + required property int extra + + anchors.right: parent.right + anchors.margins: 8 + + color: DynamicColors.palette.m3tertiary + radius: 8 + + implicitWidth: count.implicitWidth + 8 * 2 + implicitHeight: count.implicitHeight + 4 * 2 + + opacity: extra > 0 ? 1 : 0 + scale: extra > 0 ? 1 : 0.5 + + Elevation { + anchors.fill: parent + radius: parent.radius + opacity: parent.opacity + z: -1 + level: 2 + } + + CustomText { + id: count + + anchors.centerIn: parent + animate: parent.opacity > 0 + text: qsTr("+%1").arg(parent.extra) + color: DynamicColors.palette.m3onTertiary + } + + Behavior on opacity { + Anim { + duration: MaterialEasing.expressiveEffectsTime + } + } + + Behavior on scale { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/FilledSlider.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/FilledSlider.qml new file mode 100644 index 0000000..f5d3615 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/FilledSlider.qml @@ -0,0 +1,146 @@ +import QtQuick +import QtQuick.Templates +import qs.Helpers +import qs.Config +import qs.Modules + +Slider { + id: root + + required property string icon + property real oldValue + property bool initialized + property color color: DynamicColors.palette.m3secondary + + orientation: Qt.Vertical + + background: CustomRect { + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.full + + CustomRect { + anchors.left: parent.left + anchors.right: parent.right + + y: root.handle.y + implicitHeight: parent.height - y + + color: root.color + radius: parent.radius + } + } + + handle: Item { + id: handle + + property alias moving: icon.moving + + y: root.visualPosition * (root.availableHeight - height) + implicitWidth: root.width + implicitHeight: root.width + + Elevation { + anchors.fill: parent + radius: rect.radius + level: handleInteraction.containsMouse ? 2 : 1 + } + + CustomRect { + id: rect + + anchors.fill: parent + + color: DynamicColors.palette.m3inverseSurface + radius: Appearance.rounding.full + + MouseArea { + id: handleInteraction + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.NoButton + } + + MaterialIcon { + id: icon + + property bool moving + + function update(): void { + animate = !moving; + binding.when = moving; + font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger; + font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material; + } + + text: root.icon + color: DynamicColors.palette.m3inverseOnSurface + anchors.centerIn: parent + + onMovingChanged: anim.restart() + + Binding { + id: binding + + target: icon + property: "text" + value: Math.round(root.value * 100) + when: false + } + + SequentialAnimation { + id: anim + + Anim { + target: icon + property: "scale" + to: 0 + duration: Appearance.anim.durations.normal / 2 + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + ScriptAction { + script: icon.update() + } + Anim { + target: icon + property: "scale" + to: 1 + duration: Appearance.anim.durations.normal / 2 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } + } + } + + onPressedChanged: handle.moving = pressed + + onValueChanged: { + if (!initialized) { + initialized = true; + return; + } + if (Math.abs(value - oldValue) < 0.01) + return; + oldValue = value; + handle.moving = true; + stateChangeDelay.restart(); + } + + Timer { + id: stateChangeDelay + + interval: 500 + onTriggered: { + if (!root.pressed) + handle.moving = false; + } + } + + Behavior on value { + Anim { + duration: Appearance.anim.durations.large + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/IconButton.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/IconButton.qml new file mode 100644 index 0000000..6bbc64c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/IconButton.qml @@ -0,0 +1,82 @@ +import qs.Config +import qs.Modules +import QtQuick + +CustomRect { + id: root + + enum Type { + Filled, + Tonal, + Text + } + + property alias icon: label.text + property bool checked + property bool toggle + property real padding: type === IconButton.Text ? 10 / 2 : 7 + property alias font: label.font + property int type: IconButton.Filled + property bool disabled + + property alias stateLayer: stateLayer + property alias label: label + property alias radiusAnim: radiusAnim + + property bool internalChecked + property color activeColour: type === IconButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary + property color inactiveColour: { + if (!toggle && type === IconButton.Filled) + return DynamicColors.palette.m3primary; + return type === IconButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer; + } + property color activeOnColour: type === IconButton.Filled ? DynamicColors.palette.m3onPrimary : type === IconButton.Tonal ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3primary + property color inactiveOnColour: { + if (!toggle && type === IconButton.Filled) + return DynamicColors.palette.m3onPrimary; + return type === IconButton.Tonal ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurfaceVariant; + } + property color disabledColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1) + property color disabledOnColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38) + + signal clicked + + onCheckedChanged: internalChecked = checked + + radius: internalChecked ? 6 : implicitHeight / 2 * Math.min(1, 1) + color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour + + implicitWidth: implicitHeight + implicitHeight: label.implicitHeight + padding * 2 + + StateLayer { + id: stateLayer + + color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour + disabled: root.disabled + + function onClicked(): void { + if (root.toggle) + root.internalChecked = !root.internalChecked; + root.clicked(); + } + } + + MaterialIcon { + id: label + + anchors.centerIn: parent + color: root.disabled ? root.disabledOnColour : root.internalChecked ? root.activeOnColour : root.inactiveOnColour + fill: !root.toggle || root.internalChecked ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + Behavior on radius { + Anim { + id: radiusAnim + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/MaterialIcon.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/MaterialIcon.qml new file mode 100644 index 0000000..08a0792 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/MaterialIcon.qml @@ -0,0 +1,15 @@ +import qs.Config + +CustomText { + property real fill + property int grade: DynamicColors.light ? 0 : -25 + + font.family: "Material Symbols Rounded" + font.pointSize: 15 + font.variableAxes: ({ + FILL: fill.toFixed(1), + GRAD: grade, + opsz: fontInfo.pixelSize, + wght: fontInfo.weight + }) +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/OpacityMask.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/OpacityMask.qml new file mode 100644 index 0000000..22e4249 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/OpacityMask.qml @@ -0,0 +1,9 @@ +import Quickshell +import QtQuick + +ShaderEffect { + required property Item source + required property Item maskSource + + fragmentShader: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/shaders/opacitymask.frag.qsb`) +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/Ref.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Ref.qml new file mode 100644 index 0000000..0a694a4 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Ref.qml @@ -0,0 +1,8 @@ +import QtQuick + +QtObject { + required property var service + + Component.onCompleted: service.refCount++ + Component.onDestruction: service.refCount-- +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/StateLayer.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/StateLayer.qml new file mode 100644 index 0000000..6b58449 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/StateLayer.qml @@ -0,0 +1,96 @@ +import qs.Config +import qs.Modules +import QtQuick + +MouseArea { + id: root + + property bool disabled + property color color: DynamicColors.palette.m3onSurface + property real radius: parent?.radius ?? 0 + property alias rect: hoverLayer + + function onClicked(): void { + } + + anchors.fill: parent + + enabled: !disabled + cursorShape: disabled ? undefined : Qt.PointingHandCursor + hoverEnabled: true + + onPressed: event => { + if (disabled) + return; + + rippleAnim.x = event.x; + rippleAnim.y = event.y; + + const dist = (ox, oy) => ox * ox + oy * oy; + rippleAnim.radius = Math.sqrt(Math.max(dist(event.x, event.y), dist(event.x, height - event.y), dist(width - event.x, event.y), dist(width - event.x, height - event.y))); + + rippleAnim.restart(); + } + + onClicked: event => !disabled && onClicked(event) + + SequentialAnimation { + id: rippleAnim + + property real x + property real y + property real radius + + PropertyAction { + target: ripple + property: "x" + value: rippleAnim.x + } + PropertyAction { + target: ripple + property: "y" + value: rippleAnim.y + } + PropertyAction { + target: ripple + property: "opacity" + value: 0.08 + } + Anim { + target: ripple + properties: "implicitWidth,implicitHeight" + from: 0 + to: rippleAnim.radius * 2 + easing.bezierCurve: MaterialEasing.standardDecel + } + Anim { + target: ripple + property: "opacity" + to: 0 + } + } + + CustomClippingRect { + id: hoverLayer + + anchors.fill: parent + border.pixelAligned: false + + color: Qt.alpha(root.color, root.disabled ? 0 : root.pressed ? 0.1 : root.containsMouse ? 0.08 : 0) + radius: root.radius + + CustomRect { + id: ripple + + radius: 1000 + color: root.color + opacity: 0 + border.pixelAligned: false + + transform: Translate { + x: -ripple.width / 2 + y: -ripple.height / 2 + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/Toast/ToastItem.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Toast/ToastItem.qml new file mode 100644 index 0000000..a245813 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Toast/ToastItem.qml @@ -0,0 +1,135 @@ +import ZShell +import QtQuick +import QtQuick.Layouts +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config + +CustomRect { + id: root + + required property Toast modelData + + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.normal + color: { + if (root.modelData.type === Toast.Success) + return DynamicColors.palette.m3successContainer; + if (root.modelData.type === Toast.Warning) + return DynamicColors.palette.m3secondary; + if (root.modelData.type === Toast.Error) + return DynamicColors.palette.m3errorContainer; + return DynamicColors.palette.m3surface; + } + + border.width: 1 + border.color: { + let colour = DynamicColors.palette.m3outlineVariant; + if (root.modelData.type === Toast.Success) + colour = DynamicColors.palette.m3success; + if (root.modelData.type === Toast.Warning) + colour = DynamicColors.palette.m3secondaryContainer; + if (root.modelData.type === Toast.Error) + colour = DynamicColors.palette.m3error; + return Qt.alpha(colour, 0.3); + } + + Elevation { + anchors.fill: parent + radius: parent.radius + opacity: parent.opacity + z: -1 + level: 3 + } + + RowLayout { + id: layout + + anchors.fill: parent + anchors.margins: Appearance.padding.smaller + anchors.leftMargin: Appearance.padding.normal + anchors.rightMargin: Appearance.padding.normal + spacing: Appearance.spacing.normal + + CustomRect { + radius: Appearance.rounding.normal + color: { + if (root.modelData.type === Toast.Success) + return DynamicColors.palette.m3success; + if (root.modelData.type === Toast.Warning) + return DynamicColors.palette.m3secondaryContainer; + if (root.modelData.type === Toast.Error) + return DynamicColors.palette.m3error; + return DynamicColors.palette.m3surfaceContainerHigh; + } + + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.smaller * 2 + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: root.modelData.icon + color: { + if (root.modelData.type === Toast.Success) + return DynamicColors.palette.m3onSuccess; + if (root.modelData.type === Toast.Warning) + return DynamicColors.palette.m3onSecondaryContainer; + if (root.modelData.type === Toast.Error) + return DynamicColors.palette.m3onError; + return DynamicColors.palette.m3onSurfaceVariant; + } + font.pointSize: Math.round(Appearance.font.size.large * 1.2) + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + CustomText { + id: title + + Layout.fillWidth: true + text: root.modelData.title + color: { + if (root.modelData.type === Toast.Success) + return DynamicColors.palette.m3onSuccessContainer; + if (root.modelData.type === Toast.Warning) + return DynamicColors.palette.m3onSecondary; + if (root.modelData.type === Toast.Error) + return DynamicColors.palette.m3onErrorContainer; + return DynamicColors.palette.m3onSurface; + } + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + + CustomText { + Layout.fillWidth: true + textFormat: Text.StyledText + text: root.modelData.message + color: { + if (root.modelData.type === Toast.Success) + return DynamicColors.palette.m3onSuccessContainer; + if (root.modelData.type === Toast.Warning) + return DynamicColors.palette.m3onSecondary; + if (root.modelData.type === Toast.Error) + return DynamicColors.palette.m3onErrorContainer; + return DynamicColors.palette.m3onSurface; + } + opacity: 0.8 + elide: Text.ElideRight + } + } + } + + Behavior on border.color { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Components/Toast/Toasts.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Toast/Toasts.qml new file mode 100644 index 0000000..3846166 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Components/Toast/Toasts.qml @@ -0,0 +1,144 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Modules +import ZShell +import Quickshell +import QtQuick + +Item { + id: root + + readonly property int spacing: Appearance.spacing.small + property bool flag + + implicitWidth: Config.utilities.sizes.toastWidth - Appearance.padding.normal * 2 + implicitHeight: { + let h = -spacing; + for (let i = 0; i < repeater.count; i++) { + const item = repeater.itemAt(i) as ToastWrapper; + if (!item.modelData.closed && !item.previewHidden) + h += item.implicitHeight + spacing; + } + return h; + } + + Repeater { + id: repeater + + model: ScriptModel { + values: { + const toasts = []; + let count = 0; + for (const toast of Toaster.toasts) { + toasts.push(toast); + if (!toast.closed) { + count++; + if (count > Config.utilities.maxToasts) + break; + } + } + return toasts; + } + onValuesChanged: root.flagChanged() + } + + ToastWrapper {} + } + + component ToastWrapper: MouseArea { + id: toast + + required property int index + required property Toast modelData + + readonly property bool previewHidden: { + let extraHidden = 0; + for (let i = 0; i < index; i++) + if (Toaster.toasts[i].closed) + extraHidden++; + return index >= Config.utilities.maxToasts + extraHidden; + } + + onPreviewHiddenChanged: { + if (initAnim.running && previewHidden) + initAnim.stop(); + } + + opacity: modelData.closed || previewHidden ? 0 : 1 + scale: modelData.closed || previewHidden ? 0.7 : 1 + + anchors.bottomMargin: { + root.flag; // Force update + let y = 0; + for (let i = 0; i < index; i++) { + const item = repeater.itemAt(i) as ToastWrapper; + if (item && !item.modelData.closed && !item.previewHidden) + y += item.implicitHeight + root.spacing; + } + return y; + } + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + implicitHeight: toastInner.implicitHeight + + acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton + onClicked: modelData.close() + + Component.onCompleted: modelData.lock(this) + + Anim { + id: initAnim + + Component.onCompleted: running = !toast.previewHidden + + target: toast + properties: "opacity,scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + + ParallelAnimation { + running: toast.modelData.closed + onStarted: toast.anchors.bottomMargin = toast.anchors.bottomMargin + onFinished: toast.modelData.unlock(toast) + + Anim { + target: toast + property: "opacity" + to: 0 + } + Anim { + target: toast + property: "scale" + to: 0.7 + } + } + + ToastItem { + id: toastInner + + modelData: toast.modelData + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on anchors.bottomMargin { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/AccentColor.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/AccentColor.qml new file mode 100644 index 0000000..2964332 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/AccentColor.qml @@ -0,0 +1,12 @@ +import Quickshell.Io + +JsonObject { + property Accents accents: Accents {} + + component Accents: JsonObject { + property string primary: "#4080ff" + property string primaryAlt: "#60a0ff" + property string warning: "#ff6b6b" + property string warningAlt: "#ff8787" + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Appearance.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Appearance.qml new file mode 100644 index 0000000..00efc96 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Appearance.qml @@ -0,0 +1,14 @@ +pragma Singleton + +import Quickshell + +Singleton { + // Literally just here to shorten accessing stuff :woe: + // Also kinda so I can keep accessing it with `Appearance.xxx` instead of `Conf.appearance.xxx` + readonly property AppearanceConf.Rounding rounding: Config.appearance.rounding + readonly property AppearanceConf.Spacing spacing: Config.appearance.spacing + readonly property AppearanceConf.Padding padding: Config.appearance.padding + readonly property AppearanceConf.FontStuff font: Config.appearance.font + readonly property AppearanceConf.Anim anim: Config.appearance.anim + readonly property AppearanceConf.Transparency transparency: Config.appearance.transparency +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/AppearanceConf.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/AppearanceConf.qml new file mode 100644 index 0000000..5ccaec5 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/AppearanceConf.qml @@ -0,0 +1,94 @@ +import Quickshell.Io + +JsonObject { + property Rounding rounding: Rounding {} + property Spacing spacing: Spacing {} + property Padding padding: Padding {} + property FontStuff font: FontStuff {} + property Anim anim: Anim {} + property Transparency transparency: Transparency {} + + component Rounding: JsonObject { + property real scale: 1 + property int small: 12 * scale + property int normal: 17 * scale + property int large: 25 * scale + property int full: 1000 * scale + } + + component Spacing: JsonObject { + property real scale: 1 + property int small: 7 * scale + property int smaller: 10 * scale + property int normal: 12 * scale + property int larger: 15 * scale + property int large: 20 * scale + } + + component Padding: JsonObject { + property real scale: 1 + property int small: 5 * scale + property int smaller: 7 * scale + property int normal: 10 * scale + property int larger: 12 * scale + property int large: 15 * scale + } + + component FontFamily: JsonObject { + property string sans: "Segoe UI Variable Text" + property string mono: "CaskaydiaCove NF" + property string material: "Material Symbols Rounded" + property string clock: "Rubik" + } + + component FontSize: JsonObject { + property real scale: 1 + property int small: 11 * scale + property int smaller: 12 * scale + property int normal: 13 * scale + property int larger: 15 * scale + property int large: 18 * scale + property int extraLarge: 28 * scale + } + + component FontStuff: JsonObject { + property FontFamily family: FontFamily {} + property FontSize size: FontSize {} + } + + component AnimCurves: JsonObject { + property list emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] + property list emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] + property list emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1] + property list standard: [0.2, 0, 0, 1, 1, 1] + property list standardAccel: [0.3, 0, 1, 1, 1, 1] + property list standardDecel: [0, 0, 0, 1, 1, 1] + property list expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1] + property list expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1] + property list expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1] + } + + component AnimDurations: JsonObject { + property real scale: 1 + property int small: 200 * scale + property int normal: 400 * scale + property int large: 600 * scale + property int extraLarge: 1000 * scale + property int expressiveFastSpatial: 350 * scale + property int expressiveDefaultSpatial: 500 * scale + property int expressiveEffects: 200 * scale + } + + component Anim: JsonObject { + property real mediaGifSpeedAdjustment: 300 + property real sessionGifSpeed: 0.7 + property AnimCurves curves: AnimCurves {} + property AnimDurations durations: AnimDurations {} + } + + component Transparency: JsonObject { + property bool enabled: false + property real base: 0.85 + property real layers: 0.4 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/BackgroundConfig.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/BackgroundConfig.qml new file mode 100644 index 0000000..f34b832 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/BackgroundConfig.qml @@ -0,0 +1,7 @@ +import Quickshell.Io +import qs.Config + +JsonObject { + property int wallFadeDuration: MaterialEasing.standardTime + property bool enabled: true +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/BarConfig.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/BarConfig.qml new file mode 100644 index 0000000..cddf9e9 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/BarConfig.qml @@ -0,0 +1,72 @@ +import Quickshell.Io + +JsonObject { + property bool autoHide: false + property int rounding: 8 + property Popouts popouts: Popouts {} + + property list entries: [ + { + id: "workspaces", + enabled: true + }, + { + id: "audio", + enabled: true + }, + { + id: "resources", + enabled: true + }, + { + id: "updates", + enabled: true + }, + { + id: "dash", + enabled: true + }, + { + id: "spacer", + enabled: true + }, + { + id: "activeWindow", + enabled: true + }, + { + id: "spacer", + enabled: true + }, + { + id: "tray", + enabled: true + }, + { + id: "upower", + enabled: false + }, + { + id: "network", + enabled: false + }, + { + id: "clock", + enabled: true + }, + { + id: "notifBell", + enabled: true + }, + ] + + component Popouts: JsonObject { + property bool tray: true + property bool audio: true + property bool activeWindow: true + property bool resources: true + property bool clock: true + property bool network: true + property bool upower: true + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Colors.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Colors.qml new file mode 100644 index 0000000..287ea02 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Colors.qml @@ -0,0 +1,5 @@ +import Quickshell.Io + +JsonObject { + property string schemeType: "vibrant" +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Config.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Config.qml new file mode 100644 index 0000000..6908c40 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Config.qml @@ -0,0 +1,380 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import ZShell +import QtQuick +import qs.Modules as Modules +import qs.Helpers +import qs.Paths + +Singleton { + id: root + + property alias background: adapter.background + property alias barConfig: adapter.barConfig + property alias lock: adapter.lock + property alias overview: adapter.overview + property alias services: adapter.services + property alias notifs: adapter.notifs + property alias sidebar: adapter.sidebar + property alias utilities: adapter.utilities + property alias general: adapter.general + property alias dashboard: adapter.dashboard + property alias appearance: adapter.appearance + property alias osd: adapter.osd + property alias launcher: adapter.launcher + property alias colors: adapter.colors + + function save(): void { + saveTimer.restart(); + recentlySaved = true; + recentSaveCooldown.restart(); + } + + property bool recentlySaved: false + + ElapsedTimer { + id: timer + } + + Timer { + id: saveTimer + + interval: 500 + onTriggered: { + timer.restart(); + try { + let config = {}; + try { + config = JSON.parse(fileView.text()); + } catch (e) { + config = {}; + } + + config = root.serializeConfig(); + + fileView.setText(JSON.stringify(config, null, 4)); + } catch (e) { + Toaster.toast(qsTr("Failed to serialize config"), e.message, "settings_alert", Toast.Error); + } + } + } + + Timer { + id: recentSaveCooldown + + interval: 2000 + onTriggered: { + root.recentlySaved = false; + } + } + + function serializeConfig(): var { + return { + barConfig: serializeBar(), + lock: serializeLock(), + general: serializeGeneral(), + services: serializeServices(), + notifs: serializeNotifs(), + sidebar: serializeSidebar(), + utilities: serializeUtilities(), + dashboard: serializeDashboard(), + appearance: serializeAppearance(), + osd: serializeOsd(), + background: serializeBackground(), + launcher: serializeLauncher(), + colors: serializeColors() + } + } + + function serializeBar(): var { + return { + autoHide: barConfig.autoHide, + rounding: barConfig.rounding, + popouts: { + tray: barConfig.popouts.tray, + audio: barConfig.popouts.audio, + activeWindow: barConfig.popouts.activeWindow, + resources: barConfig.popouts.resources, + clock: barConfig.popouts.clock, + network: barConfig.popouts.network, + upower: barConfig.popouts.upower + }, + entries: barConfig.entries + } + } + + function serializeLock(): var { + return { + recolorLogo: lock.recolorLogo, + enableFprint: lock.enableFprint, + maxFprintTries: lock.maxFprintTries, + blurAmount: lock.blurAmount, + sizes: { + heightMult: lock.sizes.heightMult, + ratio: lock.sizes.ratio, + centerWidth: lock.sizes.centerWidth + } + }; + } + + function serializeGeneral(): var { + return { + logo: general.logo, + wallpaperPath: general.wallpaperPath, + color: { + wallust: general.color.wallust, + mode: general.color.mode, + schemeGeneration: general.color.schemeGeneration, + scheduleDarkStart: general.color.scheduleDarkStart, + scheduleDarkEnd: general.color.scheduleDarkEnd, + neovimColors: general.color.neovimColors + }, + apps: { + terminal: general.apps.terminal, + audio: general.apps.audio, + playback: general.apps.playback, + explorer: general.apps.explorer, + }, + idle: { + timouts: general.idle.timeouts + } + } + } + + function serializeServices(): var { + return { + weatherLocation: services.weatherLocation, + useFahrenheit: services.useFahrenheit, + useTwelveHourClock: services.useTwelveHourClock, + gpuType: services.gpuType, + audioIncrement: services.audioIncrement, + brightnessIncrement: services.brightnessIncrement, + maxVolume: services.maxVolume, + defaultPlayer: services.defaultPlayer, + playerAliases: services.playerAliases + }; + } + + function serializeNotifs(): var { + return { + expire: notifs.expire, + defaultExpireTimeout: notifs.defaultExpireTimeout, + clearThreshold: notifs.clearThreshold, + expandThreshold: notifs.expandThreshold, + actionOnClick: notifs.actionOnClick, + groupPreviewNum: notifs.groupPreviewNum, + sizes: { + width: notifs.sizes.width, + image: notifs.sizes.image, + badge: notifs.sizes.badge + } + }; + } + + function serializeSidebar(): var { + return { + enabled: sidebar.enabled, + sizes: { + width: sidebar.sizes.width + } + }; + } + + function serializeUtilities(): var { + return { + enabled: utilities.enabled, + maxToasts: utilities.maxToasts, + sizes: { + width: utilities.sizes.width, + toastWidth: utilities.sizes.toastWidth + }, + toasts: { + configLoaded: utilities.toasts.configLoaded, + chargingChanged: utilities.toasts.chargingChanged, + gameModeChanged: utilities.toasts.gameModeChanged, + dndChanged: utilities.toasts.dndChanged, + audioOutputChanged: utilities.toasts.audioOutputChanged, + audioInputChanged: utilities.toasts.audioInputChanged, + capsLockChanged: utilities.toasts.capsLockChanged, + numLockChanged: utilities.toasts.numLockChanged, + kbLayoutChanged: utilities.toasts.kbLayoutChanged, + vpnChanged: utilities.toasts.vpnChanged, + nowPlaying: utilities.toasts.nowPlaying + }, + vpn: { + enabled: utilities.vpn.enabled, + provider: utilities.vpn.provider + } + }; + } + + function serializeDashboard(): var { + return { + enabled: dashboard.enabled, + mediaUpdateInterval: dashboard.mediaUpdateInterval, + dragThreshold: dashboard.dragThreshold, + sizes: { + tabIndicatorHeight: dashboard.sizes.tabIndicatorHeight, + tabIndicatorSpacing: dashboard.sizes.tabIndicatorSpacing, + infoWidth: dashboard.sizes.infoWidth, + infoIconSize: dashboard.sizes.infoIconSize, + dateTimeWidth: dashboard.sizes.dateTimeWidth, + mediaWidth: dashboard.sizes.mediaWidth, + mediaProgressSweep: dashboard.sizes.mediaProgressSweep, + mediaProgressThickness: dashboard.sizes.mediaProgressThickness, + resourceProgessThickness: dashboard.sizes.resourceProgessThickness, + weatherWidth: dashboard.sizes.weatherWidth, + mediaCoverArtSize: dashboard.sizes.mediaCoverArtSize, + mediaVisualiserSize: dashboard.sizes.mediaVisualiserSize, + resourceSize: dashboard.sizes.resourceSize + } + }; + } + + function serializeOsd(): var { + return { + enabled: osd.enabled, + hideDelay: osd.hideDelay, + enableBrightness: osd.enableBrightness, + enableMicrophone: osd.enableMicrophone, + allMonBrightness: osd.allMonBrightness, + sizes: { + sliderWidth: osd.sizes.sliderWidth, + sliderHeight: osd.sizes.sliderHeight + } + }; + } + + function serializeLauncher(): var { + return { + maxAppsShown: launcher.maxAppsShown, + maxWallpapers: launcher.maxWallpapers, + actionPrefix: launcher.actionPrefix, + specialPrefix: launcher.specialPrefix, + useFuzzy: { + apps: launcher.useFuzzy.apps, + actions: launcher.useFuzzy.actions, + schemes: launcher.useFuzzy.schemes, + variants: launcher.useFuzzy.variants, + wallpapers: launcher.useFuzzy.wallpapers + }, + sizes: { + itemWidth: launcher.sizes.itemWidth, + itemHeight: launcher.sizes.itemHeight, + wallpaperWidth: launcher.sizes.wallpaperWidth, + wallpaperHeight: launcher.sizes.wallpaperHeight + }, + actions: launcher.actions + } + } + + function serializeBackground(): var { + return { + wallFadeDuration: background.wallFadeDuration, + enabled: background.enabled + } + } + + function serializeAppearance(): var { + return { + rounding: { + scale: appearance.rounding.scale + }, + spacing: { + scale: appearance.spacing.scale + }, + padding: { + scale: appearance.padding.scale + }, + font: { + family: { + sans: appearance.font.family.sans, + mono: appearance.font.family.mono, + material: appearance.font.family.material, + clock: appearance.font.family.clock + }, + size: { + scale: appearance.font.size.scale + } + }, + anim: { + mediaGifSpeedAdjustment: 300, + sessionGifSpeed: 0.7, + durations: { + scale: appearance.anim.durations.scale + } + }, + transparency: { + enabled: appearance.transparency.enabled, + base: appearance.transparency.base, + layers: appearance.transparency.layers + } + }; + } + + function serializeColors(): var { + return { + schemeType: colors.schemeType, + } + } + + FileView { + id: fileView + + path: `${Paths.config}/config.json` + + watchChanges: true + + onFileChanged: { + if ( !root.recentlySaved ) { + timer.restart(); + reload(); + } else { + reload(); + } + } + + onLoaded: { + ModeScheduler.checkStartup(); + try { + JSON.parse(text()); + const elapsed = timer.elapsedMs(); + + if ( adapter.utilities.toasts.configLoaded && !root.recentlySaved ) { + Toaster.toast(qsTr("Config loaded"), qsTr("Config loaded in %1ms").arg(elapsed), "rule_settings"); + } else if ( adapter.utilities.toasts.configLoaded && root.recentlySaved ) { + Toaster.toast(qsTr("Config saved"), qsTr("Config reloaded in %1ms").arg(elapsed), "settings_alert"); + } + } catch (e) { + Toaster.toast(qsTr("Failed to load config"), e.message, "settings_alert", Toast.Error); + } + } + + onLoadFailed: err => { + if ( err !== FileViewError.FileNotFound ) + Toaster.toast(qsTr("Failed to read config"), FileViewError.toString(err), "settings_alert", Toast.Warning); + } + + onSaveFailed: err => Toaster.toast(qsTr("Failed to save config"), FileViewError.toString(err), "settings_alert", Toast.Error) + + JsonAdapter { + id: adapter + property BackgroundConfig background: BackgroundConfig {} + property BarConfig barConfig: BarConfig {} + property LockConf lock: LockConf {} + property Overview overview: Overview {} + property Services services: Services {} + property NotifConfig notifs: NotifConfig {} + property SidebarConfig sidebar: SidebarConfig {} + property UtilConfig utilities: UtilConfig {} + property General general: General {} + property DashboardConfig dashboard: DashboardConfig {} + property AppearanceConf appearance: AppearanceConf {} + property Osd osd: Osd {} + property Launcher launcher: Launcher {} + property Colors colors: Colors {} + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/DashboardConfig.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/DashboardConfig.qml new file mode 100644 index 0000000..f1034fb --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/DashboardConfig.qml @@ -0,0 +1,24 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property int mediaUpdateInterval: 500 + property int dragThreshold: 50 + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + readonly property int tabIndicatorHeight: 3 + readonly property int tabIndicatorSpacing: 5 + readonly property int infoWidth: 200 + readonly property int infoIconSize: 25 + readonly property int dateTimeWidth: 110 + readonly property int mediaWidth: 200 + readonly property int mediaProgressSweep: 180 + readonly property int mediaProgressThickness: 8 + readonly property int resourceProgessThickness: 10 + readonly property int weatherWidth: 250 + readonly property int mediaCoverArtSize: 150 + readonly property int mediaVisualiserSize: 80 + readonly property int resourceSize: 200 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/DynamicColors.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/DynamicColors.qml new file mode 100644 index 0000000..284a2db --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/DynamicColors.qml @@ -0,0 +1,278 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import QtQuick +import ZShell +import qs.Helpers +import qs.Paths + +Singleton { + id: root + + property bool showPreview + property string scheme + property string flavour + readonly property bool light: showPreview ? previewLight : currentLight + property bool currentLight + property bool previewLight + readonly property M3Palette palette: showPreview ? preview : current + readonly property M3TPalette tPalette: M3TPalette {} + readonly property M3Palette current: M3Palette {} + readonly property M3Palette preview: M3Palette {} + readonly property Transparency transparency: Transparency {} + readonly property alias wallLuminance: analyser.luminance + + function getLuminance(c: color): real { + if (c.r == 0 && c.g == 0 && c.b == 0) + return 0; + return Math.sqrt(0.299 * (c.r ** 2) + 0.587 * (c.g ** 2) + 0.114 * (c.b ** 2)); + } + + function alterColor(c: color, a: real, layer: int): color { + const luminance = getLuminance(c); + + const offset = (!light || layer == 1 ? 1 : -layer / 2) * (light ? 0.2 : 0.3) * (1 - transparency.base) * (1 + wallLuminance * (light ? (layer == 1 ? 3 : 1) : 2.5)); + const scale = (luminance + offset) / luminance; + const r = Math.max(0, Math.min(1, c.r * scale)); + const g = Math.max(0, Math.min(1, c.g * scale)); + const b = Math.max(0, Math.min(1, c.b * scale)); + + return Qt.rgba(r, g, b, a); + } + + function layer(c: color, layer: var): color { + if (!transparency.enabled) + return c; + + return layer === 0 ? Qt.alpha(c, transparency.base) : alterColor(c, transparency.layers, layer ?? 1); + } + + function on(c: color): color { + if (c.hslLightness < 0.5) + return Qt.hsla(c.hslHue, c.hslSaturation, 0.9, 1); + return Qt.hsla(c.hslHue, c.hslSaturation, 0.1, 1); + } + + function load(data: string, isPreview: bool): void { + const colors = isPreview ? preview : current; + const scheme = JSON.parse(data); + + if (!isPreview) { + root.scheme = scheme.name; + flavour = scheme.flavor; + currentLight = scheme.mode === "light"; + } else { + previewLight = scheme.mode === "light"; + } + + for (const [name, color] of Object.entries(scheme.colors)) { + const propName = name.startsWith("term") ? name : `m3${name}`; + if (colors.hasOwnProperty(propName)) + colors[propName] = `${color}`; + } + } + + FileView { + path: `${Paths.state}/scheme.json` + watchChanges: true + onFileChanged: reload() + onLoaded: root.load(text(), false) + } + + ImageAnalyser { + id: analyser + + source: WallpaperPath.currentWallpaperPath + } + + component Transparency: QtObject { + readonly property bool enabled: Appearance.transparency.enabled + readonly property real base: Appearance.transparency.base - (root.light ? 0.1 : 0) + readonly property real layers: Appearance.transparency.layers + } + + component M3TPalette: QtObject { + readonly property color m3primary_paletteKeyColor: root.layer(root.palette.m3primary_paletteKeyColor) + readonly property color m3secondary_paletteKeyColor: root.layer(root.palette.m3secondary_paletteKeyColor) + readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor) + readonly property color m3neutral_paletteKeyColor: root.layer(root.palette.m3neutral_paletteKeyColor) + readonly property color m3neutral_variant_paletteKeyColor: root.layer(root.palette.m3neutral_variant_paletteKeyColor) + readonly property color m3background: root.layer(root.palette.m3background, 0) + readonly property color m3onBackground: root.layer(root.palette.m3onBackground) + readonly property color m3surface: root.layer(root.palette.m3surface, 0) + readonly property color m3surfaceDim: root.layer(root.palette.m3surfaceDim, 0) + readonly property color m3surfaceBright: root.layer(root.palette.m3surfaceBright, 0) + readonly property color m3surfaceContainerLowest: root.layer(root.palette.m3surfaceContainerLowest) + readonly property color m3surfaceContainerLow: root.layer(root.palette.m3surfaceContainerLow) + readonly property color m3surfaceContainer: root.layer(root.palette.m3surfaceContainer) + readonly property color m3surfaceContainerHigh: root.layer(root.palette.m3surfaceContainerHigh) + readonly property color m3surfaceContainerHighest: root.layer(root.palette.m3surfaceContainerHighest) + readonly property color m3onSurface: root.layer(root.palette.m3onSurface) + readonly property color m3surfaceVariant: root.layer(root.palette.m3surfaceVariant, 0) + readonly property color m3onSurfaceVariant: root.layer(root.palette.m3onSurfaceVariant) + readonly property color m3inverseSurface: root.layer(root.palette.m3inverseSurface, 0) + readonly property color m3inverseOnSurface: root.layer(root.palette.m3inverseOnSurface) + readonly property color m3outline: root.layer(root.palette.m3outline) + readonly property color m3outlineVariant: root.layer(root.palette.m3outlineVariant) + readonly property color m3shadow: root.layer(root.palette.m3shadow) + readonly property color m3scrim: root.layer(root.palette.m3scrim) + readonly property color m3surfaceTint: root.layer(root.palette.m3surfaceTint) + readonly property color m3primary: root.layer(root.palette.m3primary) + readonly property color m3onPrimary: root.layer(root.palette.m3onPrimary) + readonly property color m3primaryContainer: root.layer(root.palette.m3primaryContainer) + readonly property color m3onPrimaryContainer: root.layer(root.palette.m3onPrimaryContainer) + readonly property color m3inversePrimary: root.layer(root.palette.m3inversePrimary) + readonly property color m3secondary: root.layer(root.palette.m3secondary) + readonly property color m3onSecondary: root.layer(root.palette.m3onSecondary) + readonly property color m3secondaryContainer: root.layer(root.palette.m3secondaryContainer) + readonly property color m3onSecondaryContainer: root.layer(root.palette.m3onSecondaryContainer) + readonly property color m3tertiary: root.layer(root.palette.m3tertiary) + readonly property color m3onTertiary: root.layer(root.palette.m3onTertiary) + readonly property color m3tertiaryContainer: root.layer(root.palette.m3tertiaryContainer) + readonly property color m3onTertiaryContainer: root.layer(root.palette.m3onTertiaryContainer) + readonly property color m3error: root.layer(root.palette.m3error) + readonly property color m3onError: root.layer(root.palette.m3onError) + readonly property color m3errorContainer: root.layer(root.palette.m3errorContainer) + readonly property color m3onErrorContainer: root.layer(root.palette.m3onErrorContainer) + readonly property color m3success: root.layer(root.palette.m3success) + readonly property color m3onSuccess: root.layer(root.palette.m3onSuccess) + readonly property color m3successContainer: root.layer(root.palette.m3successContainer) + readonly property color m3onSuccessContainer: root.layer(root.palette.m3onSuccessContainer) + readonly property color m3primaryFixed: root.layer(root.palette.m3primaryFixed) + readonly property color m3primaryFixedDim: root.layer(root.palette.m3primaryFixedDim) + readonly property color m3onPrimaryFixed: root.layer(root.palette.m3onPrimaryFixed) + readonly property color m3onPrimaryFixedVariant: root.layer(root.palette.m3onPrimaryFixedVariant) + readonly property color m3secondaryFixed: root.layer(root.palette.m3secondaryFixed) + readonly property color m3secondaryFixedDim: root.layer(root.palette.m3secondaryFixedDim) + readonly property color m3onSecondaryFixed: root.layer(root.palette.m3onSecondaryFixed) + readonly property color m3onSecondaryFixedVariant: root.layer(root.palette.m3onSecondaryFixedVariant) + readonly property color m3tertiaryFixed: root.layer(root.palette.m3tertiaryFixed) + readonly property color m3tertiaryFixedDim: root.layer(root.palette.m3tertiaryFixedDim) + readonly property color m3onTertiaryFixed: root.layer(root.palette.m3onTertiaryFixed) + readonly property color m3onTertiaryFixedVariant: root.layer(root.palette.m3onTertiaryFixedVariant) + } + + component M3Palette: QtObject { + property color m3primary_paletteKeyColor: "#a8627b" + property color m3secondary_paletteKeyColor: "#8e6f78" + property color m3tertiary_paletteKeyColor: "#986e4c" + property color m3neutral_paletteKeyColor: "#807477" + property color m3neutral_variant_paletteKeyColor: "#837377" + property color m3background: "#191114" + property color m3onBackground: "#efdfe2" + property color m3surface: "#191114" + property color m3surfaceDim: "#191114" + property color m3surfaceBright: "#403739" + property color m3surfaceContainerLowest: "#130c0e" + property color m3surfaceContainerLow: "#22191c" + property color m3surfaceContainer: "#261d20" + property color m3surfaceContainerHigh: "#31282a" + property color m3surfaceContainerHighest: "#3c3235" + property color m3onSurface: "#efdfe2" + property color m3surfaceVariant: "#514347" + property color m3onSurfaceVariant: "#d5c2c6" + property color m3inverseSurface: "#efdfe2" + property color m3inverseOnSurface: "#372e30" + property color m3outline: "#9e8c91" + property color m3outlineVariant: "#514347" + property color m3shadow: "#000000" + property color m3scrim: "#000000" + property color m3surfaceTint: "#ffb0ca" + property color m3primary: "#ffb0ca" + property color m3onPrimary: "#541d34" + property color m3primaryContainer: "#6f334a" + property color m3onPrimaryContainer: "#ffd9e3" + property color m3inversePrimary: "#8b4a62" + property color m3secondary: "#e2bdc7" + property color m3onSecondary: "#422932" + property color m3secondaryContainer: "#5a3f48" + property color m3onSecondaryContainer: "#ffd9e3" + property color m3tertiary: "#f0bc95" + property color m3onTertiary: "#48290c" + property color m3tertiaryContainer: "#b58763" + property color m3onTertiaryContainer: "#000000" + property color m3error: "#ffb4ab" + property color m3onError: "#690005" + property color m3errorContainer: "#93000a" + property color m3onErrorContainer: "#ffdad6" + property color m3success: "#B5CCBA" + property color m3onSuccess: "#213528" + property color m3successContainer: "#374B3E" + property color m3onSuccessContainer: "#D1E9D6" + property color m3primaryFixed: "#ffd9e3" + property color m3primaryFixedDim: "#ffb0ca" + property color m3onPrimaryFixed: "#39071f" + property color m3onPrimaryFixedVariant: "#6f334a" + property color m3secondaryFixed: "#ffd9e3" + property color m3secondaryFixedDim: "#e2bdc7" + property color m3onSecondaryFixed: "#2b151d" + property color m3onSecondaryFixedVariant: "#5a3f48" + property color m3tertiaryFixed: "#ffdcc3" + property color m3tertiaryFixedDim: "#f0bc95" + property color m3onTertiaryFixed: "#2f1500" + property color m3onTertiaryFixedVariant: "#623f21" + } + + component M3MaccchiatoPalette: QtObject { + property color m3primary_paletteKeyColor: "#6a73ac" + property color m3secondary_paletteKeyColor: "#72758e" + property color m3tertiary_paletteKeyColor: "#9b6592" + property color m3neutral_paletteKeyColor: "#77767b" + property color m3neutral_variant_paletteKeyColor: "#767680" + property color m3background: "#131317" + property color m3onBackground: "#e4e1e7" + property color m3surface: "#131317" + property color m3surfaceDim: "#131317" + property color m3surfaceBright: "#39393d" + property color m3surfaceContainerLowest: "#0e0e12" + property color m3surfaceContainerLow: "#1b1b1f" + property color m3surfaceContainer: "#1f1f23" + property color m3surfaceContainerHigh: "#2a2a2e" + property color m3surfaceContainerHighest: "#353438" + property color m3onSurface: "#e4e1e7" + property color m3surfaceVariant: "#46464f" + property color m3onSurfaceVariant: "#c6c5d1" + property color m3inverseSurface: "#e4e1e7" + property color m3inverseOnSurface: "#303034" + property color m3outline: "#90909a" + property color m3outlineVariant: "#46464f" + property color m3shadow: "#000000" + property color m3scrim: "#000000" + property color m3surfaceTint: "#bac3ff" + property color m3primary: "#bac3ff" + property color m3onPrimary: "#232c60" + property color m3primaryContainer: "#6a73ac" + property color m3onPrimaryContainer: "#ffffff" + property color m3inversePrimary: "#525b92" + property color m3secondary: "#c3c5e0" + property color m3onSecondary: "#2c2f44" + property color m3secondaryContainer: "#42455c" + property color m3onSecondaryContainer: "#b1b3ce" + property color m3tertiary: "#f1b3e5" + property color m3onTertiary: "#4c1f48" + property color m3tertiaryContainer: "#b77ead" + property color m3onTertiaryContainer: "#000000" + property color m3error: "#ffb4ab" + property color m3onError: "#690005" + property color m3errorContainer: "#93000a" + property color m3onErrorContainer: "#ffdad6" + property color m3primaryFixed: "#dee0ff" + property color m3primaryFixedDim: "#bac3ff" + property color m3onPrimaryFixed: "#0b154b" + property color m3onPrimaryFixedVariant: "#3a4378" + property color m3secondaryFixed: "#dfe1fd" + property color m3secondaryFixedDim: "#c3c5e0" + property color m3onSecondaryFixed: "#171a2e" + property color m3onSecondaryFixedVariant: "#42455c" + property color m3tertiaryFixed: "#ffd7f4" + property color m3tertiaryFixedDim: "#f1b3e5" + property color m3onTertiaryFixed: "#340831" + property color m3onTertiaryFixedVariant: "#66365f" + property color m3success: "#B5CCBA" + property color m3onSuccess: "#213528" + property color m3successContainer: "#374B3E" + property color m3onSuccessContainer: "#D1E9D6" + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/General.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/General.qml new file mode 100644 index 0000000..2633bf8 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/General.qml @@ -0,0 +1,40 @@ +import Quickshell.Io +import Quickshell + +JsonObject { + property string logo: "" + property string wallpaperPath: Quickshell.env("HOME") + "/Pictures/Wallpapers" + property Color color: Color {} + property Apps apps: Apps {} + property Idle idle: Idle {} + + component Color: JsonObject { + property bool wallust: false + property bool schemeGeneration: true + property string mode: "dark" + property int scheduleDarkStart: 0 + property int scheduleDarkEnd: 0 + property bool neovimColors: false + } + + component Apps: JsonObject { + property list terminal: ["kitty"] + property list audio: ["pavucontrol"] + property list playback: ["mpv"] + property list explorer: ["dolphin"] + } + + component Idle: JsonObject { + property list timeouts: [ + { + timeout: 180, + idleAction: "lock" + }, + { + timeout: 300, + idleAction: "dpms off", + activeAction: "dpms on" + } + ] + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/IdleTimeout.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/IdleTimeout.qml new file mode 100644 index 0000000..c1db937 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/IdleTimeout.qml @@ -0,0 +1,15 @@ +import Quickshell.Io + +JsonObject { + property list timeouts: [ + { + timeout: 180, + idleAction: "lock" + }, + { + timeout: 300, + idleAction: "dpms off", + activeAction: "dpms on" + } + ] +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Launcher.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Launcher.qml new file mode 100644 index 0000000..6ce97f9 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Launcher.qml @@ -0,0 +1,84 @@ +import Quickshell.Io + +JsonObject { + property int maxAppsShown: 10 + property int maxWallpapers: 7 + property string actionPrefix: ">" + property string specialPrefix: "@" + property Sizes sizes: Sizes {} + property UseFuzzy useFuzzy: UseFuzzy {} + + component UseFuzzy: JsonObject { + property bool apps: false + property bool actions: false + property bool schemes: false + property bool variants: false + property bool wallpapers: false + } + + component Sizes: JsonObject { + property int itemWidth: 600 + property int itemHeight: 50 + property int wallpaperWidth: 280 + property int wallpaperHeight: 200 + } + + property list actions: [ + { + name: "Calculator", + icon: "calculate", + description: "Do simple math equations (powered by Qalc)", + command: ["autocomplete", "calc"], + enabled: true, + dangerous: false + }, + { + name: "Wallpaper", + icon: "image", + description: "Change the current wallpaper", + command: ["autocomplete", "wallpaper"], + enabled: true, + dangerous: false + }, + { + name: "Shutdown", + icon: "power_settings_new", + description: "Shutdown the system", + command: ["systemctl", "poweroff"], + enabled: true, + dangerous: true + }, + { + name: "Reboot", + icon: "cached", + description: "Reboot the system", + command: ["systemctl", "reboot"], + enabled: true, + dangerous: true + }, + { + name: "Logout", + icon: "exit_to_app", + description: "Log out of the current session", + command: ["loginctl", "terminate-user", ""], + enabled: true, + dangerous: true + }, + { + name: "Lock", + icon: "lock", + description: "Lock the current session", + command: ["loginctl", "lock-session"], + enabled: true, + dangerous: false + }, + { + name: "Sleep", + icon: "bedtime", + description: "Suspend then hibernate", + command: ["systemctl", "suspend-then-hibernate"], + enabled: true, + dangerous: false + }, + ] +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/LockConf.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/LockConf.qml new file mode 100644 index 0000000..011dc86 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/LockConf.qml @@ -0,0 +1,15 @@ +import Quickshell.Io + +JsonObject { + property bool recolorLogo: false + property bool enableFprint: true + property int maxFprintTries: 3 + property Sizes sizes: Sizes {} + property int blurAmount: 40 + + component Sizes: JsonObject { + property real heightMult: 0.7 + property real ratio: 16 / 9 + property int centerWidth: 600 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/MaterialEasing.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/MaterialEasing.qml new file mode 100644 index 0000000..cbd4718 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/MaterialEasing.qml @@ -0,0 +1,27 @@ +pragma Singleton +import Quickshell + +Singleton { + id: root + + property real scale: Appearance.anim.durations.scale + + readonly property list emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] + readonly property list emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] + readonly property int emphasizedAccelTime: 200 * scale + readonly property list emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1] + readonly property int emphasizedDecelTime: 400 * scale + readonly property int emphasizedTime: 500 * scale + readonly property list expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1] + readonly property int expressiveDefaultSpatialTime: 500 * scale + readonly property list expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1] + readonly property int expressiveEffectsTime: 200 * scale + readonly property list expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1] + readonly property int expressiveFastSpatialTime: 350 * scale + readonly property list standard: [0.2, 0, 0, 1, 1, 1] + readonly property list standardAccel: [0.3, 0, 1, 1, 1, 1] + readonly property int standardAccelTime: 200 * scale + readonly property list standardDecel: [0, 0, 0, 1, 1, 1] + readonly property int standardDecelTime: 250 * scale + readonly property int standardTime: 300 * scale +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/NotifConfig.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/NotifConfig.qml new file mode 100644 index 0000000..8f68ba4 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/NotifConfig.qml @@ -0,0 +1,18 @@ +import Quickshell.Io + +JsonObject { + property bool expire: true + property int defaultExpireTimeout: 5000 + property real clearThreshold: 0.3 + property int expandThreshold: 20 + property bool actionOnClick: false + property int groupPreviewNum: 3 + property bool openExpanded: false + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property int width: 400 + property int image: 41 + property int badge: 20 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Osd.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Osd.qml new file mode 100644 index 0000000..36f716e --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Osd.qml @@ -0,0 +1,15 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property int hideDelay: 3000 + property bool enableBrightness: true + property bool enableMicrophone: true + property bool allMonBrightness: false + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property int sliderWidth: 30 + property int sliderHeight: 150 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Overview.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Overview.qml new file mode 100644 index 0000000..6f81758 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Overview.qml @@ -0,0 +1,8 @@ +import Quickshell.Io + +JsonObject { + property int rows: 2 + property int columns: 5 + property real scale: 0.16 + property bool enable: false +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Services.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Services.qml new file mode 100644 index 0000000..668a9cd --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Services.qml @@ -0,0 +1,19 @@ +import Quickshell.Io +import QtQuick + +JsonObject { + property string weatherLocation: "" + property bool useFahrenheit: false + property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a") + property string gpuType: "" + property real audioIncrement: 0.1 + property real brightnessIncrement: 0.1 + property real maxVolume: 1.0 + property string defaultPlayer: "Spotify" + property list playerAliases: [ + { + "from": "com.github.th_ch.youtube_music", + "to": "YT Music" + } + ] +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/SidebarConfig.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/SidebarConfig.qml new file mode 100644 index 0000000..ba48822 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/SidebarConfig.qml @@ -0,0 +1,10 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property int width: 430 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/Transparency.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Transparency.qml new file mode 100644 index 0000000..e3df2e9 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/Transparency.qml @@ -0,0 +1,7 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: false + property real base: 0.85 + property real layers: 0.4 +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/UtilConfig.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/UtilConfig.qml new file mode 100644 index 0000000..cf46446 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/UtilConfig.qml @@ -0,0 +1,35 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property int maxToasts: 4 + + property Sizes sizes: Sizes {} + property Toasts toasts: Toasts {} + property Vpn vpn: Vpn {} + + component Sizes: JsonObject { + property int width: 430 + property int toastWidth: 430 + } + + component Toasts: JsonObject { + property bool configLoaded: true + property bool chargingChanged: true + property bool gameModeChanged: true + property bool dndChanged: true + property bool audioOutputChanged: true + property bool audioInputChanged: true + property bool capsLockChanged: true + property bool numLockChanged: true + property bool kbLayoutChanged: true + property bool kbLimit: true + property bool vpnChanged: true + property bool nowPlaying: false + } + + component Vpn: JsonObject { + property bool enabled: false + property list provider: ["netbird"] + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Config/WorkspaceWidget.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Config/WorkspaceWidget.qml new file mode 100644 index 0000000..cf3e293 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Config/WorkspaceWidget.qml @@ -0,0 +1,6 @@ +import Quickshell.Io + +JsonObject { + property string textColor: "black" + property string inactiveTextColor: "white" +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Audio.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Audio.qml new file mode 100644 index 0000000..51b6095 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Audio.qml @@ -0,0 +1,144 @@ +pragma Singleton + +import qs.Config +import ZShell.Services +import ZShell +import Quickshell +import Quickshell.Services.Pipewire +import QtQuick + +Singleton { + id: root + + property string previousSinkName: "" + property string previousSourceName: "" + + readonly property var nodes: Pipewire.nodes.values.reduce((acc, node) => { + if (!node.isStream) { + if (node.isSink) + acc.sinks.push(node); + else if (node.audio) + acc.sources.push(node); + } else if (node.isStream && node.audio) { + // Application streams (output streams) + acc.streams.push(node); + } + return acc; + }, { + sources: [], + sinks: [], + streams: [] + }) + + readonly property list sinks: nodes.sinks + readonly property list sources: nodes.sources + readonly property list streams: nodes.streams + + readonly property PwNode sink: Pipewire.defaultAudioSink + readonly property PwNode source: Pipewire.defaultAudioSource + + readonly property bool muted: !!sink?.audio?.muted + readonly property real volume: sink?.audio?.volume ?? 0 + + readonly property bool sourceMuted: !!source?.audio?.muted + readonly property real sourceVolume: source?.audio?.volume ?? 0 + + function setVolume(newVolume: real): void { + if (sink?.ready && sink?.audio) { + sink.audio.muted = false; + sink.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume)); + } + } + + function incrementVolume(amount: real): void { + setVolume(volume + (amount || Config.services.audioIncrement)); + } + + function decrementVolume(amount: real): void { + setVolume(volume - (amount || Config.services.audioIncrement)); + } + + function setSourceVolume(newVolume: real): void { + if (source?.ready && source?.audio) { + source.audio.muted = false; + source.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume)); + } + } + + function incrementSourceVolume(amount: real): void { + setSourceVolume(sourceVolume + (amount || Config.services.audioIncrement)); + } + + function decrementSourceVolume(amount: real): void { + setSourceVolume(sourceVolume - (amount || Config.services.audioIncrement)); + } + + function setAudioSink(newSink: PwNode): void { + Pipewire.preferredDefaultAudioSink = newSink; + } + + function setAudioSource(newSource: PwNode): void { + Pipewire.preferredDefaultAudioSource = newSource; + } + + function setStreamVolume(stream: PwNode, newVolume: real): void { + if (stream?.ready && stream?.audio) { + stream.audio.muted = false; + stream.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume)); + } + } + + function setStreamMuted(stream: PwNode, muted: bool): void { + if (stream?.ready && stream?.audio) { + stream.audio.muted = muted; + } + } + + function getStreamVolume(stream: PwNode): real { + return stream?.audio?.volume ?? 0; + } + + function getStreamMuted(stream: PwNode): bool { + return !!stream?.audio?.muted; + } + + function getStreamName(stream: PwNode): string { + if (!stream) + return qsTr("Unknown"); + // Try application name first, then description, then name + return stream.applicationName || stream.description || stream.name || qsTr("Unknown Application"); + } + + onSinkChanged: { + if (!sink?.ready) + return; + + const newSinkName = sink.description || sink.name || qsTr("Unknown Device"); + + if (previousSinkName && previousSinkName !== newSinkName && Config.utilities.toasts.audioOutputChanged) + Toaster.toast(qsTr("Audio output changed"), qsTr("Now using: %1").arg(newSinkName), "volume_up"); + + previousSinkName = newSinkName; + } + + onSourceChanged: { + if (!source?.ready) + return; + + const newSourceName = source.description || source.name || qsTr("Unknown Device"); + + if (previousSourceName && previousSourceName !== newSourceName && Config.utilities.toasts.audioInputChanged) + Toaster.toast(qsTr("Audio input changed"), qsTr("Now using: %1").arg(newSourceName), "mic"); + + previousSourceName = newSourceName; + } + + Component.onCompleted: { + previousSinkName = sink?.description || sink?.name || qsTr("Unknown Device"); + previousSourceName = source?.description || source?.name || qsTr("Unknown Device"); + } + + PwObjectTracker { + objects: [...root.sinks, ...root.sources, ...root.streams] + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Network.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Network.qml new file mode 100644 index 0000000..be89dbf --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Network.qml @@ -0,0 +1,323 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + Component.onCompleted: { + // Trigger ethernet device detection after initialization + Qt.callLater(() => { + getEthernetDevices(); + }); + // Load saved connections on startup + Nmcli.loadSavedConnections(() => { + root.savedConnections = Nmcli.savedConnections; + root.savedConnectionSsids = Nmcli.savedConnectionSsids; + }); + // Get initial WiFi status + Nmcli.getWifiStatus(enabled => { + root.wifiEnabled = enabled; + }); + // Sync networks from Nmcli on startup + Qt.callLater(() => { + syncNetworksFromNmcli(); + }, 100); + } + + readonly property list networks: [] + readonly property AccessPoint active: networks.find(n => n.active) ?? null + property bool wifiEnabled: true + readonly property bool scanning: Nmcli.scanning + + property list ethernetDevices: [] + readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null + property int ethernetDeviceCount: 0 + property bool ethernetProcessRunning: false + property var ethernetDeviceDetails: null + property var wirelessDeviceDetails: null + + function enableWifi(enabled: bool): void { + Nmcli.enableWifi(enabled, result => { + if (result.success) { + root.getWifiStatus(); + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + } + }); + } + + function toggleWifi(): void { + Nmcli.toggleWifi(result => { + if (result.success) { + root.getWifiStatus(); + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + } + }); + } + + function rescanWifi(): void { + Nmcli.rescanWifi(); + } + + property var pendingConnection: null + signal connectionFailed(string ssid) + + function connectToNetwork(ssid: string, password: string, bssid: string, callback: var): void { + // Set up pending connection tracking if callback provided + if (callback) { + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + root.pendingConnection = { + ssid: ssid, + bssid: hasBssid ? bssid : "", + callback: callback + }; + } + + Nmcli.connectToNetwork(ssid, password, bssid, result => { + if (result && result.success) { + // Connection successful + if (callback) + callback(result); + root.pendingConnection = null; + } else if (result && result.needsPassword) { + // Password needed - callback will handle showing dialog + if (callback) + callback(result); + } else { + // Connection failed + if (result && result.error) { + root.connectionFailed(ssid); + } + if (callback) + callback(result); + root.pendingConnection = null; + } + }); + } + + function connectToNetworkWithPasswordCheck(ssid: string, isSecure: bool, callback: var, bssid: string): void { + // Set up pending connection tracking + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + root.pendingConnection = { + ssid: ssid, + bssid: hasBssid ? bssid : "", + callback: callback + }; + + Nmcli.connectToNetworkWithPasswordCheck(ssid, isSecure, result => { + if (result && result.success) { + // Connection successful + if (callback) + callback(result); + root.pendingConnection = null; + } else if (result && result.needsPassword) { + // Password needed - callback will handle showing dialog + if (callback) + callback(result); + } else { + // Connection failed + if (result && result.error) { + root.connectionFailed(ssid); + } + if (callback) + callback(result); + root.pendingConnection = null; + } + }, bssid); + } + + function disconnectFromNetwork(): void { + // Try to disconnect - use connection name if available, otherwise use device + Nmcli.disconnectFromNetwork(); + // Refresh network list after disconnection + Qt.callLater(() => { + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + }, 500); + } + + function forgetNetwork(ssid: string): void { + // Delete the connection profile for this network + // This will remove the saved password and connection settings + Nmcli.forgetNetwork(ssid, result => { + if (result.success) { + // Refresh network list after deletion + Qt.callLater(() => { + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + }, 500); + } + }); + } + + property list savedConnections: [] + property list savedConnectionSsids: [] + + // Sync saved connections from Nmcli when they're updated + Connections { + target: Nmcli + function onSavedConnectionsChanged() { + root.savedConnections = Nmcli.savedConnections; + } + function onSavedConnectionSsidsChanged() { + root.savedConnectionSsids = Nmcli.savedConnectionSsids; + } + } + + function syncNetworksFromNmcli(): void { + const rNetworks = root.networks; + const nNetworks = Nmcli.networks; + + // Build a map of existing networks by key + const existingMap = new Map(); + for (const rn of rNetworks) { + const key = `${rn.frequency}:${rn.ssid}:${rn.bssid}`; + existingMap.set(key, rn); + } + + // Build a map of new networks by key + const newMap = new Map(); + for (const nn of nNetworks) { + const key = `${nn.frequency}:${nn.ssid}:${nn.bssid}`; + newMap.set(key, nn); + } + + // Remove networks that no longer exist + for (const [key, network] of existingMap) { + if (!newMap.has(key)) { + const index = rNetworks.indexOf(network); + if (index >= 0) { + rNetworks.splice(index, 1); + network.destroy(); + } + } + } + + // Add or update networks from Nmcli + for (const [key, nNetwork] of newMap) { + const existing = existingMap.get(key); + if (existing) { + // Update existing network's lastIpcObject + existing.lastIpcObject = nNetwork.lastIpcObject; + } else { + // Create new AccessPoint from Nmcli's data + rNetworks.push(apComp.createObject(root, { + lastIpcObject: nNetwork.lastIpcObject + })); + } + } + } + + component AccessPoint: QtObject { + required property var lastIpcObject + readonly property string ssid: lastIpcObject.ssid + readonly property string bssid: lastIpcObject.bssid + readonly property int strength: lastIpcObject.strength + readonly property int frequency: lastIpcObject.frequency + readonly property bool active: lastIpcObject.active + readonly property string security: lastIpcObject.security + readonly property bool isSecure: security.length > 0 + } + + Component { + id: apComp + AccessPoint {} + } + + function hasSavedProfile(ssid: string): bool { + // Use Nmcli's hasSavedProfile which has the same logic + return Nmcli.hasSavedProfile(ssid); + } + + function getWifiStatus(): void { + Nmcli.getWifiStatus(enabled => { + root.wifiEnabled = enabled; + }); + } + + function getEthernetDevices(): void { + root.ethernetProcessRunning = true; + Nmcli.getEthernetInterfaces(interfaces => { + root.ethernetDevices = Nmcli.ethernetDevices; + root.ethernetDeviceCount = Nmcli.ethernetDevices.length; + root.ethernetProcessRunning = false; + }); + } + + function connectEthernet(connectionName: string, interfaceName: string): void { + Nmcli.connectEthernet(connectionName, interfaceName, result => { + if (result.success) { + getEthernetDevices(); + // Refresh device details after connection + Qt.callLater(() => { + const activeDevice = root.ethernetDevices.find(function (d) { + return d.connected; + }); + if (activeDevice && activeDevice.interface) { + updateEthernetDeviceDetails(activeDevice.interface); + } + }, 1000); + } + }); + } + + function disconnectEthernet(connectionName: string): void { + Nmcli.disconnectEthernet(connectionName, result => { + if (result.success) { + getEthernetDevices(); + // Clear device details after disconnection + Qt.callLater(() => { + root.ethernetDeviceDetails = null; + }); + } + }); + } + + function updateEthernetDeviceDetails(interfaceName: string): void { + Nmcli.getEthernetDeviceDetails(interfaceName, details => { + root.ethernetDeviceDetails = details; + }); + } + + function updateWirelessDeviceDetails(): void { + // Find the wireless interface by looking for wifi devices + // Pass empty string to let Nmcli find the active interface automatically + Nmcli.getWirelessDeviceDetails("", details => { + root.wirelessDeviceDetails = details; + }); + } + + function cidrToSubnetMask(cidr: string): string { + // Convert CIDR notation (e.g., "24") to subnet mask (e.g., "255.255.255.0") + const cidrNum = parseInt(cidr); + if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { + return ""; + } + + const mask = (0xffffffff << (32 - cidrNum)) >>> 0; + const octets = [(mask >>> 24) & 0xff, (mask >>> 16) & 0xff, (mask >>> 8) & 0xff, mask & 0xff]; + + return octets.join("."); + } + + Process { + running: true + command: ["nmcli", "m"] + stdout: SplitParser { + onRead: { + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + getEthernetDevices(); + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Nmcli.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Nmcli.qml new file mode 100644 index 0000000..36bd3e6 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/Nmcli.qml @@ -0,0 +1,1352 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property var deviceStatus: null + property var wirelessInterfaces: [] + property var ethernetInterfaces: [] + property bool isConnected: false + property string activeInterface: "" + property string activeConnection: "" + property bool wifiEnabled: true + readonly property bool scanning: rescanProc.running + readonly property list networks: [] + readonly property AccessPoint active: networks.find(n => n.active) ?? null + property list savedConnections: [] + property list savedConnectionSsids: [] + + property var wifiConnectionQueue: [] + property int currentSsidQueryIndex: 0 + property var pendingConnection: null + signal connectionFailed(string ssid) + property var wirelessDeviceDetails: null + property var ethernetDeviceDetails: null + property list ethernetDevices: [] + readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null + + property list activeProcesses: [] + + // Constants + readonly property string deviceTypeWifi: "wifi" + readonly property string deviceTypeEthernet: "ethernet" + readonly property string connectionTypeWireless: "802-11-wireless" + readonly property string nmcliCommandDevice: "device" + readonly property string nmcliCommandConnection: "connection" + readonly property string nmcliCommandWifi: "wifi" + readonly property string nmcliCommandRadio: "radio" + readonly property string deviceStatusFields: "DEVICE,TYPE,STATE,CONNECTION" + readonly property string connectionListFields: "NAME,TYPE" + readonly property string wirelessSsidField: "802-11-wireless.ssid" + readonly property string networkListFields: "SSID,SIGNAL,SECURITY" + readonly property string networkDetailFields: "ACTIVE,SIGNAL,FREQ,SSID,BSSID,SECURITY" + readonly property string securityKeyMgmt: "802-11-wireless-security.key-mgmt" + readonly property string securityPsk: "802-11-wireless-security.psk" + readonly property string keyMgmtWpaPsk: "wpa-psk" + readonly property string connectionParamType: "type" + readonly property string connectionParamConName: "con-name" + readonly property string connectionParamIfname: "ifname" + readonly property string connectionParamSsid: "ssid" + readonly property string connectionParamPassword: "password" + readonly property string connectionParamBssid: "802-11-wireless.bssid" + + function detectPasswordRequired(error: string): bool { + if (!error || error.length === 0) { + return false; + } + + return (error.includes("Secrets were required") || error.includes("Secrets were required, but not provided") || error.includes("No secrets provided") || error.includes("802-11-wireless-security.psk") || error.includes("password for") || (error.includes("password") && !error.includes("Connection activated") && !error.includes("successfully")) || (error.includes("Secrets") && !error.includes("Connection activated") && !error.includes("successfully")) || (error.includes("802.11") && !error.includes("Connection activated") && !error.includes("successfully"))) && !error.includes("Connection activated") && !error.includes("successfully"); + } + + function parseNetworkOutput(output: string): list { + if (!output || output.length === 0) { + return []; + } + + const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED"; + const rep = new RegExp("\\\\:", "g"); + const rep2 = new RegExp(PLACEHOLDER, "g"); + + const allNetworks = output.trim().split("\n").filter(line => line && line.length > 0).map(n => { + const net = n.replace(rep, PLACEHOLDER).split(":"); + return { + active: net[0] === "yes", + strength: parseInt(net[1] || "0", 10) || 0, + frequency: parseInt(net[2] || "0", 10) || 0, + ssid: (net[3]?.replace(rep2, ":") ?? "").trim(), + bssid: (net[4]?.replace(rep2, ":") ?? "").trim(), + security: (net[5] ?? "").trim() + }; + }).filter(n => n.ssid && n.ssid.length > 0); + + return allNetworks; + } + + function deduplicateNetworks(networks: list): list { + if (!networks || networks.length === 0) { + return []; + } + + const networkMap = new Map(); + for (const network of networks) { + const existing = networkMap.get(network.ssid); + if (!existing) { + networkMap.set(network.ssid, network); + } else { + if (network.active && !existing.active) { + networkMap.set(network.ssid, network); + } else if (!network.active && !existing.active) { + if (network.strength > existing.strength) { + networkMap.set(network.ssid, network); + } + } + } + } + + return Array.from(networkMap.values()); + } + + function isConnectionCommand(command: list): bool { + if (!command || command.length === 0) { + return false; + } + + return command.includes(root.nmcliCommandWifi) || command.includes(root.nmcliCommandConnection); + } + + function parseDeviceStatusOutput(output: string, filterType: string): list { + if (!output || output.length === 0) { + return []; + } + + const interfaces = []; + const lines = output.trim().split("\n"); + + for (const line of lines) { + const parts = line.split(":"); + if (parts.length >= 2) { + const deviceType = parts[1]; + let shouldInclude = false; + + if (filterType === root.deviceTypeWifi && deviceType === root.deviceTypeWifi) { + shouldInclude = true; + } else if (filterType === root.deviceTypeEthernet && deviceType === root.deviceTypeEthernet) { + shouldInclude = true; + } else if (filterType === "both" && (deviceType === root.deviceTypeWifi || deviceType === root.deviceTypeEthernet)) { + shouldInclude = true; + } + + if (shouldInclude) { + interfaces.push({ + device: parts[0] || "", + type: parts[1] || "", + state: parts[2] || "", + connection: parts[3] || "" + }); + } + } + } + + return interfaces; + } + + function isConnectedState(state: string): bool { + if (!state || state.length === 0) { + return false; + } + + return state === "100 (connected)" || state === "connected" || state.startsWith("connected"); + } + + function executeCommand(args: list, callback: var): void { + const proc = commandProc.createObject(root); + proc.command = ["nmcli", ...args]; + proc.callback = callback; + + activeProcesses.push(proc); + + proc.processFinished.connect(() => { + const index = activeProcesses.indexOf(proc); + if (index >= 0) { + activeProcesses.splice(index, 1); + } + }); + + Qt.callLater(() => { + proc.exec(proc.command); + }); + } + + function getDeviceStatus(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + if (callback) + callback(result.output); + }); + } + + function getWirelessInterfaces(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + const interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeWifi); + root.wirelessInterfaces = interfaces; + if (callback) + callback(interfaces); + }); + } + + function getEthernetInterfaces(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + const interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeEthernet); + const devices = []; + + for (const iface of interfaces) { + const connected = isConnectedState(iface.state); + + devices.push({ + interface: iface.device, + type: iface.type, + state: iface.state, + connection: iface.connection, + connected: connected, + ipAddress: "", + gateway: "", + dns: [], + subnet: "", + macAddress: "", + speed: "" + }); + } + + root.ethernetInterfaces = interfaces; + root.ethernetDevices = devices; + if (callback) + callback(interfaces); + }); + } + + function connectEthernet(connectionName: string, interfaceName: string, callback: var): void { + if (connectionName && connectionName.length > 0) { + executeCommand([root.nmcliCommandConnection, "up", connectionName], result => { + if (result.success) { + Qt.callLater(() => { + getEthernetInterfaces(() => {}); + if (interfaceName && interfaceName.length > 0) { + Qt.callLater(() => { + getEthernetDeviceDetails(interfaceName, () => {}); + }, 1000); + } + }, 500); + } + if (callback) + callback(result); + }); + } else if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => { + if (result.success) { + Qt.callLater(() => { + getEthernetInterfaces(() => {}); + Qt.callLater(() => { + getEthernetDeviceDetails(interfaceName, () => {}); + }, 1000); + }, 500); + } + if (callback) + callback(result); + }); + } else { + if (callback) + callback({ + success: false, + output: "", + error: "No connection name or interface specified", + exitCode: -1 + }); + } + } + + function disconnectEthernet(connectionName: string, callback: var): void { + if (!connectionName || connectionName.length === 0) { + if (callback) + callback({ + success: false, + output: "", + error: "No connection name specified", + exitCode: -1 + }); + return; + } + + executeCommand([root.nmcliCommandConnection, "down", connectionName], result => { + if (result.success) { + root.ethernetDeviceDetails = null; + Qt.callLater(() => { + getEthernetInterfaces(() => {}); + }, 500); + } + if (callback) + callback(result); + }); + } + + function getAllInterfaces(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + const interfaces = parseDeviceStatusOutput(result.output, "both"); + if (callback) + callback(interfaces); + }); + } + + function isInterfaceConnected(interfaceName: string, callback: var): void { + executeCommand([root.nmcliCommandDevice, "status"], result => { + const lines = result.output.trim().split("\n"); + for (const line of lines) { + const parts = line.split(/\s+/); + if (parts.length >= 3 && parts[0] === interfaceName) { + const connected = isConnectedState(parts[2]); + if (callback) + callback(connected); + return; + } + } + if (callback) + callback(false); + }); + } + + function connectToNetworkWithPasswordCheck(ssid: string, isSecure: bool, callback: var, bssid: string): void { + if (isSecure) { + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + connectWireless(ssid, "", bssid, result => { + if (result.success) { + if (callback) + callback({ + success: true, + usedSavedPassword: true, + output: result.output, + error: "", + exitCode: 0 + }); + } else if (result.needsPassword) { + if (callback) + callback({ + success: false, + needsPassword: true, + output: result.output, + error: result.error, + exitCode: result.exitCode + }); + } else { + if (callback) + callback(result); + } + }); + } else { + connectWireless(ssid, "", bssid, callback); + } + } + + function connectToNetwork(ssid: string, password: string, bssid: string, callback: var): void { + connectWireless(ssid, password, bssid, callback); + } + + function connectWireless(ssid: string, password: string, bssid: string, callback: var, retryCount: int): void { + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + const retries = retryCount !== undefined ? retryCount : 0; + const maxRetries = 2; + + if (callback) { + root.pendingConnection = { + ssid: ssid, + bssid: hasBssid ? bssid : "", + callback: callback, + retryCount: retries + }; + connectionCheckTimer.start(); + immediateCheckTimer.checkCount = 0; + immediateCheckTimer.start(); + } + + if (password && password.length > 0 && hasBssid) { + const bssidUpper = bssid.toUpperCase(); + createConnectionWithPassword(ssid, bssidUpper, password, callback); + return; + } + + let cmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "connect", ssid]; + if (password && password.length > 0) { + cmd.push(root.connectionParamPassword, password); + } + executeCommand(cmd, result => { + if (result.needsPassword && callback) { + if (callback) + callback(result); + return; + } + + if (!result.success && root.pendingConnection && retries < maxRetries) { + console.warn("[NMCLI] Connection failed, retrying... (attempt " + (retries + 1) + "/" + maxRetries + ")"); + Qt.callLater(() => { + connectWireless(ssid, password, bssid, callback, retries + 1); + }, 1000); + } else if (!result.success && root.pendingConnection) {} else if (result.success && callback) {} else if (!result.success && !root.pendingConnection) { + if (callback) + callback(result); + } + }); + } + + function createConnectionWithPassword(ssid: string, bssidUpper: string, password: string, callback: var): void { + checkAndDeleteConnection(ssid, () => { + const cmd = [root.nmcliCommandConnection, "add", root.connectionParamType, root.deviceTypeWifi, root.connectionParamConName, ssid, root.connectionParamIfname, "*", root.connectionParamSsid, ssid, root.connectionParamBssid, bssidUpper, root.securityKeyMgmt, root.keyMgmtWpaPsk, root.securityPsk, password]; + + executeCommand(cmd, result => { + if (result.success) { + loadSavedConnections(() => {}); + activateConnection(ssid, callback); + } else { + const hasDuplicateWarning = result.error && (result.error.includes("another connection with the name") || result.error.includes("Reference the connection by its uuid")); + + if (hasDuplicateWarning || (result.exitCode > 0 && result.exitCode < 10)) { + loadSavedConnections(() => {}); + activateConnection(ssid, callback); + } else { + console.warn("[NMCLI] Connection profile creation failed, trying fallback..."); + let fallbackCmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "connect", ssid, root.connectionParamPassword, password]; + executeCommand(fallbackCmd, fallbackResult => { + if (callback) + callback(fallbackResult); + }); + } + } + }); + }); + } + + function checkAndDeleteConnection(ssid: string, callback: var): void { + executeCommand([root.nmcliCommandConnection, "show", ssid], result => { + if (result.success) { + executeCommand([root.nmcliCommandConnection, "delete", ssid], deleteResult => { + Qt.callLater(() => { + if (callback) + callback(); + }, 300); + }); + } else { + if (callback) + callback(); + } + }); + } + + function activateConnection(connectionName: string, callback: var): void { + executeCommand([root.nmcliCommandConnection, "up", connectionName], result => { + if (callback) + callback(result); + }); + } + + function loadSavedConnections(callback: var): void { + executeCommand(["-t", "-f", root.connectionListFields, root.nmcliCommandConnection, "show"], result => { + if (!result.success) { + root.savedConnections = []; + root.savedConnectionSsids = []; + if (callback) + callback([]); + return; + } + + parseConnectionList(result.output, callback); + }); + } + + function parseConnectionList(output: string, callback: var): void { + const lines = output.trim().split("\n").filter(line => line.length > 0); + const wifiConnections = []; + const connections = []; + + for (const line of lines) { + const parts = line.split(":"); + if (parts.length >= 2) { + const name = parts[0]; + const type = parts[1]; + connections.push(name); + + if (type === root.connectionTypeWireless) { + wifiConnections.push(name); + } + } + } + + root.savedConnections = connections; + + if (wifiConnections.length > 0) { + root.wifiConnectionQueue = wifiConnections; + root.currentSsidQueryIndex = 0; + root.savedConnectionSsids = []; + queryNextSsid(callback); + } else { + root.savedConnectionSsids = []; + root.wifiConnectionQueue = []; + if (callback) + callback(root.savedConnectionSsids); + } + } + + function queryNextSsid(callback: var): void { + if (root.currentSsidQueryIndex < root.wifiConnectionQueue.length) { + const connectionName = root.wifiConnectionQueue[root.currentSsidQueryIndex]; + root.currentSsidQueryIndex++; + + executeCommand(["-t", "-f", root.wirelessSsidField, root.nmcliCommandConnection, "show", connectionName], result => { + if (result.success) { + processSsidOutput(result.output); + } + queryNextSsid(callback); + }); + } else { + root.wifiConnectionQueue = []; + root.currentSsidQueryIndex = 0; + if (callback) + callback(root.savedConnectionSsids); + } + } + + function processSsidOutput(output: string): void { + const lines = output.trim().split("\n"); + for (const line of lines) { + if (line.startsWith("802-11-wireless.ssid:")) { + const ssid = line.substring("802-11-wireless.ssid:".length).trim(); + if (ssid && ssid.length > 0) { + const ssidLower = ssid.toLowerCase(); + const exists = root.savedConnectionSsids.some(s => s && s.toLowerCase() === ssidLower); + if (!exists) { + const newList = root.savedConnectionSsids.slice(); + newList.push(ssid); + root.savedConnectionSsids = newList; + } + } + } + } + } + + function hasSavedProfile(ssid: string): bool { + if (!ssid || ssid.length === 0) { + return false; + } + const ssidLower = ssid.toLowerCase().trim(); + + if (root.active && root.active.ssid) { + const activeSsidLower = root.active.ssid.toLowerCase().trim(); + if (activeSsidLower === ssidLower) { + return true; + } + } + + const hasSsid = root.savedConnectionSsids.some(savedSsid => savedSsid && savedSsid.toLowerCase().trim() === ssidLower); + + if (hasSsid) { + return true; + } + + const hasConnectionName = root.savedConnections.some(connName => connName && connName.toLowerCase().trim() === ssidLower); + + return hasConnectionName; + } + + function forgetNetwork(ssid: string, callback: var): void { + if (!ssid || ssid.length === 0) { + if (callback) + callback({ + success: false, + output: "", + error: "No SSID specified", + exitCode: -1 + }); + return; + } + + const connectionName = root.savedConnections.find(conn => conn && conn.toLowerCase().trim() === ssid.toLowerCase().trim()) || ssid; + + executeCommand([root.nmcliCommandConnection, "delete", connectionName], result => { + if (result.success) { + Qt.callLater(() => { + loadSavedConnections(() => {}); + }, 500); + } + if (callback) + callback(result); + }); + } + + function disconnect(interfaceName: string, callback: var): void { + if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => { + if (callback) + callback(result.success ? result.output : ""); + }); + } else { + executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => { + if (callback) + callback(result.success ? result.output : ""); + }); + } + } + + function disconnectFromNetwork(): void { + if (active && active.ssid) { + executeCommand([root.nmcliCommandConnection, "down", active.ssid], result => { + if (result.success) { + getNetworks(() => {}); + } + }); + } else { + executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => { + if (result.success) { + getNetworks(() => {}); + } + }); + } + } + + function getDeviceDetails(interfaceName: string, callback: var): void { + executeCommand([root.nmcliCommandDevice, "show", interfaceName], result => { + if (callback) + callback(result.output); + }); + } + + function refreshStatus(callback: var): void { + getDeviceStatus(output => { + const lines = output.trim().split("\n"); + let connected = false; + let activeIf = ""; + let activeConn = ""; + + for (const line of lines) { + const parts = line.split(":"); + if (parts.length >= 4) { + const state = parts[2] || ""; + if (isConnectedState(state)) { + connected = true; + activeIf = parts[0] || ""; + activeConn = parts[3] || ""; + break; + } + } + } + + root.isConnected = connected; + root.activeInterface = activeIf; + root.activeConnection = activeConn; + + if (callback) + callback({ + connected, + interface: activeIf, + connection: activeConn + }); + }); + } + + function bringInterfaceUp(interfaceName: string, callback: var): void { + if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => { + if (callback) { + callback(result); + } + }); + } else { + if (callback) + callback({ + success: false, + output: "", + error: "No interface specified", + exitCode: -1 + }); + } + } + + function bringInterfaceDown(interfaceName: string, callback: var): void { + if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => { + if (callback) { + callback(result); + } + }); + } else { + if (callback) + callback({ + success: false, + output: "", + error: "No interface specified", + exitCode: -1 + }); + } + } + + function scanWirelessNetworks(interfaceName: string, callback: var): void { + let cmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "rescan"]; + if (interfaceName && interfaceName.length > 0) { + cmd.push(root.connectionParamIfname, interfaceName); + } + executeCommand(cmd, result => { + if (callback) { + callback(result); + } + }); + } + + function rescanWifi(): void { + rescanProc.running = true; + } + + function enableWifi(enabled: bool, callback: var): void { + const cmd = enabled ? "on" : "off"; + executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi, cmd], result => { + if (result.success) { + getWifiStatus(status => { + root.wifiEnabled = status; + if (callback) + callback(result); + }); + } else { + if (callback) + callback(result); + } + }); + } + + function toggleWifi(callback: var): void { + const newState = !root.wifiEnabled; + enableWifi(newState, callback); + } + + function getWifiStatus(callback: var): void { + executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi], result => { + if (result.success) { + const enabled = result.output.trim() === "enabled"; + root.wifiEnabled = enabled; + if (callback) + callback(enabled); + } else { + if (callback) + callback(root.wifiEnabled); + } + }); + } + + function getNetworks(callback: var): void { + executeCommand(["-g", root.networkDetailFields, "d", "w"], result => { + if (!result.success) { + if (callback) + callback([]); + return; + } + + const allNetworks = parseNetworkOutput(result.output); + const networks = deduplicateNetworks(allNetworks); + const rNetworks = root.networks; + + const destroyed = rNetworks.filter(rn => !networks.find(n => n.frequency === rn.frequency && n.ssid === rn.ssid && n.bssid === rn.bssid)); + for (const network of destroyed) { + const index = rNetworks.indexOf(network); + if (index >= 0) { + rNetworks.splice(index, 1); + network.destroy(); + } + } + + for (const network of networks) { + const match = rNetworks.find(n => n.frequency === network.frequency && n.ssid === network.ssid && n.bssid === network.bssid); + if (match) { + match.lastIpcObject = network; + } else { + rNetworks.push(apComp.createObject(root, { + lastIpcObject: network + })); + } + } + + if (callback) + callback(root.networks); + checkPendingConnection(); + }); + } + + function getWirelessSSIDs(interfaceName: string, callback: var): void { + let cmd = ["-t", "-f", root.networkListFields, root.nmcliCommandDevice, root.nmcliCommandWifi, "list"]; + if (interfaceName && interfaceName.length > 0) { + cmd.push(root.connectionParamIfname, interfaceName); + } + executeCommand(cmd, result => { + if (!result.success) { + if (callback) + callback([]); + return; + } + + const ssids = []; + const lines = result.output.trim().split("\n"); + const seenSSIDs = new Set(); + + for (const line of lines) { + if (!line || line.length === 0) + continue; + + const parts = line.split(":"); + if (parts.length >= 1) { + const ssid = parts[0].trim(); + if (ssid && ssid.length > 0 && !seenSSIDs.has(ssid)) { + seenSSIDs.add(ssid); + const signalStr = parts.length >= 2 ? parts[1].trim() : ""; + const signal = signalStr ? parseInt(signalStr, 10) : 0; + const security = parts.length >= 3 ? parts[2].trim() : ""; + ssids.push({ + ssid: ssid, + signal: signalStr, + signalValue: isNaN(signal) ? 0 : signal, + security: security + }); + } + } + } + + ssids.sort((a, b) => { + return b.signalValue - a.signalValue; + }); + + if (callback) + callback(ssids); + }); + } + + function handlePasswordRequired(proc: var, error: string, output: string, exitCode: int): bool { + if (!proc || !error || error.length === 0) { + return false; + } + + if (!isConnectionCommand(proc.command) || !root.pendingConnection || !root.pendingConnection.callback) { + return false; + } + + const needsPassword = detectPasswordRequired(error); + + if (needsPassword && !proc.callbackCalled && root.pendingConnection) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + const pending = root.pendingConnection; + root.pendingConnection = null; + proc.callbackCalled = true; + const result = { + success: false, + output: output || "", + error: error, + exitCode: exitCode, + needsPassword: true + }; + if (pending.callback) { + pending.callback(result); + } + if (proc.callback && proc.callback !== pending.callback) { + proc.callback(result); + } + return true; + } + + return false; + } + + component CommandProcess: Process { + id: proc + + property var callback: null + property list command: [] + property bool callbackCalled: false + property int exitCode: 0 + + signal processFinished + + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + + stdout: StdioCollector { + id: stdoutCollector + } + + stderr: StdioCollector { + id: stderrCollector + + onStreamFinished: { + const error = text.trim(); + if (error && error.length > 0) { + const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; + root.handlePasswordRequired(proc, error, output, -1); + } + } + } + + onExited: code => { + exitCode = code; + + Qt.callLater(() => { + if (callbackCalled) { + processFinished(); + return; + } + + if (proc.callback) { + const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; + const error = (stderrCollector && stderrCollector.text) ? stderrCollector.text : ""; + const success = exitCode === 0; + const cmdIsConnection = isConnectionCommand(proc.command); + + if (root.handlePasswordRequired(proc, error, output, exitCode)) { + processFinished(); + return; + } + + const needsPassword = cmdIsConnection && root.detectPasswordRequired(error); + + if (!success && cmdIsConnection && root.pendingConnection) { + const failedSsid = root.pendingConnection.ssid; + root.connectionFailed(failedSsid); + } + + callbackCalled = true; + callback({ + success: success, + output: output, + error: error, + exitCode: proc.exitCode, + needsPassword: needsPassword || false + }); + processFinished(); + } else { + processFinished(); + } + }); + } + } + + Component { + id: commandProc + + CommandProcess {} + } + + component AccessPoint: QtObject { + required property var lastIpcObject + readonly property string ssid: lastIpcObject.ssid + readonly property string bssid: lastIpcObject.bssid + readonly property int strength: lastIpcObject.strength + readonly property int frequency: lastIpcObject.frequency + readonly property bool active: lastIpcObject.active + readonly property string security: lastIpcObject.security + readonly property bool isSecure: security.length > 0 + } + + Component { + id: apComp + + AccessPoint {} + } + + Timer { + id: connectionCheckTimer + + interval: 4000 + onTriggered: { + if (root.pendingConnection) { + const connected = root.active && root.active.ssid === root.pendingConnection.ssid; + + if (!connected && root.pendingConnection.callback) { + let foundPasswordError = false; + for (let i = 0; i < root.activeProcesses.length; i++) { + const proc = root.activeProcesses[i]; + if (proc && proc.stderr && proc.stderr.text) { + const error = proc.stderr.text.trim(); + if (error && error.length > 0) { + if (root.isConnectionCommand(proc.command)) { + const needsPassword = root.detectPasswordRequired(error); + + if (needsPassword && !proc.callbackCalled && root.pendingConnection) { + const pending = root.pendingConnection; + root.pendingConnection = null; + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + proc.callbackCalled = true; + const result = { + success: false, + output: (proc.stdout && proc.stdout.text) ? proc.stdout.text : "", + error: error, + exitCode: -1, + needsPassword: true + }; + if (pending.callback) { + pending.callback(result); + } + if (proc.callback && proc.callback !== pending.callback) { + proc.callback(result); + } + foundPasswordError = true; + break; + } + } + } + } + } + + if (!foundPasswordError) { + const pending = root.pendingConnection; + const failedSsid = pending.ssid; + root.pendingConnection = null; + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + root.connectionFailed(failedSsid); + pending.callback({ + success: false, + output: "", + error: "Connection timeout", + exitCode: -1, + needsPassword: false + }); + } + } else if (connected) { + root.pendingConnection = null; + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + } + } + } + } + + Timer { + id: immediateCheckTimer + + property int checkCount: 0 + + interval: 500 + repeat: true + triggeredOnStart: false + + onTriggered: { + if (root.pendingConnection) { + checkCount++; + const connected = root.active && root.active.ssid === root.pendingConnection.ssid; + + if (connected) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + if (root.pendingConnection.callback) { + root.pendingConnection.callback({ + success: true, + output: "Connected", + error: "", + exitCode: 0 + }); + } + root.pendingConnection = null; + } else { + for (let i = 0; i < root.activeProcesses.length; i++) { + const proc = root.activeProcesses[i]; + if (proc && proc.stderr && proc.stderr.text) { + const error = proc.stderr.text.trim(); + if (error && error.length > 0) { + if (root.isConnectionCommand(proc.command)) { + const needsPassword = root.detectPasswordRequired(error); + + if (needsPassword && !proc.callbackCalled && root.pendingConnection && root.pendingConnection.callback) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + const pending = root.pendingConnection; + root.pendingConnection = null; + proc.callbackCalled = true; + const result = { + success: false, + output: (proc.stdout && proc.stdout.text) ? proc.stdout.text : "", + error: error, + exitCode: -1, + needsPassword: true + }; + if (pending.callback) { + pending.callback(result); + } + if (proc.callback && proc.callback !== pending.callback) { + proc.callback(result); + } + return; + } + } + } + } + } + + if (checkCount >= 6) { + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + } + } + } else { + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + } + } + } + + function checkPendingConnection(): void { + if (root.pendingConnection) { + Qt.callLater(() => { + const connected = root.active && root.active.ssid === root.pendingConnection.ssid; + if (connected) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + if (root.pendingConnection.callback) { + root.pendingConnection.callback({ + success: true, + output: "Connected", + error: "", + exitCode: 0 + }); + } + root.pendingConnection = null; + } else { + if (!immediateCheckTimer.running) { + immediateCheckTimer.start(); + } + } + }); + } + } + + function cidrToSubnetMask(cidr: string): string { + const cidrNum = parseInt(cidr, 10); + if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { + return ""; + } + + const mask = (0xffffffff << (32 - cidrNum)) >>> 0; + const octet1 = (mask >>> 24) & 0xff; + const octet2 = (mask >>> 16) & 0xff; + const octet3 = (mask >>> 8) & 0xff; + const octet4 = mask & 0xff; + + return `${octet1}.${octet2}.${octet3}.${octet4}`; + } + + function getWirelessDeviceDetails(interfaceName: string, callback: var): void { + if (!interfaceName || interfaceName.length === 0) { + const activeInterface = root.wirelessInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeInterface && activeInterface.device) { + interfaceName = activeInterface.device; + } else { + if (callback) + callback(null); + return; + } + } + + executeCommand(["device", "show", interfaceName], result => { + if (!result.success || !result.output) { + root.wirelessDeviceDetails = null; + if (callback) + callback(null); + return; + } + + const details = parseDeviceDetails(result.output, false); + root.wirelessDeviceDetails = details; + if (callback) + callback(details); + }); + } + + function getEthernetDeviceDetails(interfaceName: string, callback: var): void { + if (!interfaceName || interfaceName.length === 0) { + const activeInterface = root.ethernetInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeInterface && activeInterface.device) { + interfaceName = activeInterface.device; + } else { + if (callback) + callback(null); + return; + } + } + + executeCommand(["device", "show", interfaceName], result => { + if (!result.success || !result.output) { + root.ethernetDeviceDetails = null; + if (callback) + callback(null); + return; + } + + const details = parseDeviceDetails(result.output, true); + root.ethernetDeviceDetails = details; + if (callback) + callback(details); + }); + } + + function parseDeviceDetails(output: string, isEthernet: bool): var { + const details = { + ipAddress: "", + gateway: "", + dns: [], + subnet: "", + macAddress: "", + speed: "" + }; + + if (!output || output.length === 0) { + return details; + } + + const lines = output.trim().split("\n"); + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const parts = line.split(":"); + if (parts.length >= 2) { + const key = parts[0].trim(); + const value = parts.slice(1).join(":").trim(); + + if (key.startsWith("IP4.ADDRESS")) { + const ipParts = value.split("/"); + details.ipAddress = ipParts[0] || ""; + if (ipParts[1]) { + details.subnet = cidrToSubnetMask(ipParts[1]); + } else { + details.subnet = ""; + } + } else if (key === "IP4.GATEWAY") { + if (value !== "--") { + details.gateway = value; + } + } else if (key.startsWith("IP4.DNS")) { + if (value !== "--" && value.length > 0) { + details.dns.push(value); + } + } else if (isEthernet && key === "WIRED-PROPERTIES.MAC") { + details.macAddress = value; + } else if (isEthernet && key === "WIRED-PROPERTIES.SPEED") { + details.speed = value; + } else if (!isEthernet && key === "GENERAL.HWADDR") { + details.macAddress = value; + } + } + } + + return details; + } + + Process { + id: rescanProc + + command: ["nmcli", "dev", root.nmcliCommandWifi, "list", "--rescan", "yes"] + onExited: root.getNetworks() + } + + Process { + id: monitorProc + + running: true + command: ["nmcli", "monitor"] + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + stdout: SplitParser { + onRead: root.refreshOnConnectionChange() + } + onExited: monitorRestartTimer.start() + } + + Timer { + id: monitorRestartTimer + interval: 2000 + onTriggered: { + monitorProc.running = true; + } + } + + function refreshOnConnectionChange(): void { + getNetworks(networks => { + const newActive = root.active; + + if (newActive && newActive.active) { + Qt.callLater(() => { + if (root.wirelessInterfaces.length > 0) { + const activeWireless = root.wirelessInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeWireless && activeWireless.device) { + getWirelessDeviceDetails(activeWireless.device, () => {}); + } + } + + if (root.ethernetInterfaces.length > 0) { + const activeEthernet = root.ethernetInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeEthernet && activeEthernet.device) { + getEthernetDeviceDetails(activeEthernet.device, () => {}); + } + } + }, 500); + } else { + root.wirelessDeviceDetails = null; + root.ethernetDeviceDetails = null; + } + + getWirelessInterfaces(() => {}); + getEthernetInterfaces(() => { + if (root.activeEthernet && root.activeEthernet.connected) { + Qt.callLater(() => { + getEthernetDeviceDetails(root.activeEthernet.interface, () => {}); + }, 500); + } + }); + }); + } + + Component.onCompleted: { + getWifiStatus(() => {}); + getNetworks(() => {}); + loadSavedConnections(() => {}); + getEthernetInterfaces(() => {}); + + Qt.callLater(() => { + if (root.wirelessInterfaces.length > 0) { + const activeWireless = root.wirelessInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeWireless && activeWireless.device) { + getWirelessDeviceDetails(activeWireless.device, () => {}); + } + } + + if (root.ethernetInterfaces.length > 0) { + const activeEthernet = root.ethernetInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeEthernet && activeEthernet.device) { + getEthernetDeviceDetails(activeEthernet.device, () => {}); + } + } + }, 2000); + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/NotifServer.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/NotifServer.qml new file mode 100644 index 0000000..6c2a5cd --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Daemons/NotifServer.qml @@ -0,0 +1,348 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import Quickshell.Services.Notifications +import Quickshell.Hyprland +import QtQuick +import ZShell +import qs.Components +import qs.Modules +import qs.Helpers +import qs.Paths +import qs.Config + +Singleton { + id: root + + property list list: [] + readonly property list notClosed: list.filter( n => !n.closed ) + readonly property list popups: list.filter( n => n.popup ) + property alias dnd: props.dnd + property alias server: server + + property bool loaded + + onListChanged: { + if ( loaded ) { + saveTimer.restart(); + } + if ( root.list.length > 0 ) { + HasNotifications.hasNotifications = true; + } else { + HasNotifications.hasNotifications = false; + } + } + + Timer { + id: saveTimer + interval: 1000 + onTriggered: storage.setText( JSON.stringify( root.notClosed.map( n => ({ + time: n.time, + id: n.id, + summary: n.summary, + body: n.body, + appIcon: n.appIcon, + appName: n.appName, + image: n.image, + expireTimeout: n.expireTimeout, + urgency: n.urgency, + resident: n.resident, + hasActionIcons: n.hasActionIcons, + actions: n.actions + })))); + } + + PersistentProperties { + id: props + + property bool dnd + + reloadableId: "notifs" + } + + NotificationServer { + id: server + + keepOnReload: false + actionsSupported: true + bodyHyperlinksSupported: true + bodyImagesSupported: true + bodyMarkupSupported: true + imageSupported: true + persistenceSupported: true + + onNotification: notif => { + notif.tracked = true; + + const comp = notifComp.createObject(root, { + popup: !props.dnd, + notification: notif + }); + root.list = [comp, ...root.list]; + } + } + + FileView { + id: storage + path: `${Paths.state}/notifs.json` + + onLoaded: { + const data = JSON.parse(text()); + for (const notif of data) + root.list.push(notifComp.createObject(root, notif)); + root.list.sort((a, b) => b.time - a.time); + root.loaded = true; + } + + onLoadFailed: err => { + if (err === FileViewError.FileNotFound) { + root.loaded = true; + setText("[]"); + } + } + } + + CustomShortcut { + name: "clearnotifs" + description: "Clear all notifications" + onPressed: { + for (const notif of root.list.slice()) + notif.close(); + } + } + + IpcHandler { + target: "notifs" + + function clear(): void { + for (const notif of root.list.slice()) + notif.close(); + } + + function isDndEnabled(): bool { + return props.dnd; + } + + function toggleDnd(): void { + props.dnd = !props.dnd; + } + + function enableDnd(): void { + props.dnd = true; + } + + function disableDnd(): void { + props.dnd = false; + } + } + + component Notif: QtObject { + id: notif + + property bool popup + property bool closed + property var locks: new Set() + + property date time: new Date() + readonly property string timeStr: { + const diff = Time.date.getTime() - time.getTime(); + const m = Math.floor(diff / 60000); + + if (m < 1) + return qsTr("now"); + + const h = Math.floor(m / 60); + const d = Math.floor(h / 24); + + if (d > 0) + return `${d}d`; + if (h > 0) + return `${h}h`; + return `${m}m`; + } + + property Notification notification + property string id + property string summary + property string body + property string appIcon + property string appName + property string image + property real expireTimeout: 5 + property int urgency: NotificationUrgency.Normal + property bool resident + property bool hasActionIcons + property list actions + + readonly property Timer timer: Timer { + property int totalTime: Config.notifs.defaultExpireTimeout + property int remainingTime: totalTime + property bool paused: false + + running: !paused + repeat: true + interval: 50 + onTriggered: { + remainingTime -= interval; + + if ( remainingTime <= 0 ) { + remainingTime = 0; + notif.popup = false; + stop(); + } + } + } + + readonly property LazyLoader dummyImageLoader: LazyLoader { + active: false + + PanelWindow { + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + color: "transparent" + mask: Region {} + + Image { + function tryCache(): void { + if (status !== Image.Ready || width != Config.notifs.sizes.image || height != Config.notifs.sizes.image) + return; + + const cacheKey = notif.appName + notif.summary + notif.id; + let h1 = 0xdeadbeef, h2 = 0x41c6ce57, ch; + for (let i = 0; i < cacheKey.length; i++) { + ch = cacheKey.charCodeAt(i); + h1 = Math.imul(h1 ^ ch, 2654435761); + h2 = Math.imul(h2 ^ ch, 1597334677); + } + h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); + h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); + h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); + h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); + const hash = (h2 >>> 0).toString(16).padStart(8, 0) + (h1 >>> 0).toString(16).padStart(8, 0); + + const cache = `${Paths.notifimagecache}/${hash}.png`; + ZShellIo.saveItem(this, Qt.resolvedUrl(cache), () => { + notif.image = cache; + notif.dummyImageLoader.active = false; + }); + } + + anchors.fill: parent + source: Qt.resolvedUrl(notif.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + opacity: 0 + + onStatusChanged: tryCache() + onWidthChanged: tryCache() + onHeightChanged: tryCache() + } + } + } + + readonly property Connections conn: Connections { + target: notif.notification + + function onClosed(): void { + notif.close(); + } + + function onSummaryChanged(): void { + notif.summary = notif.notification.summary; + } + + function onBodyChanged(): void { + notif.body = notif.notification.body; + } + + function onAppIconChanged(): void { + notif.appIcon = notif.notification.appIcon; + } + + function onAppNameChanged(): void { + notif.appName = notif.notification.appName; + } + + function onImageChanged(): void { + notif.image = notif.notification.image; + if (notif.notification?.image) + notif.dummyImageLoader.active = true; + } + + function onExpireTimeoutChanged(): void { + notif.expireTimeout = notif.notification.expireTimeout; + } + + function onUrgencyChanged(): void { + notif.urgency = notif.notification.urgency; + } + + function onResidentChanged(): void { + notif.resident = notif.notification.resident; + } + + function onHasActionIconsChanged(): void { + notif.hasActionIcons = notif.notification.hasActionIcons; + } + + function onActionsChanged(): void { + notif.actions = notif.notification.actions.map(a => ({ + identifier: a.identifier, + text: a.text, + invoke: () => a.invoke() + })); + } + } + + function lock(item: Item): void { + locks.add(item); + } + + function unlock(item: Item): void { + locks.delete(item); + if (closed) + close(); + } + + function close(): void { + closed = true; + if (locks.size === 0 && root.list.includes(this)) { + root.list = root.list.filter(n => n !== this); + notification?.dismiss(); + destroy(); + } + } + + Component.onCompleted: { + if (!notification) + return; + + id = notification.id; + summary = notification.summary; + body = notification.body; + appIcon = notification.appIcon; + appName = notification.appName; + image = notification.image; + if (notification?.image) + dummyImageLoader.active = true; + expireTimeout = notification.expireTimeout; + urgency = notification.urgency; + resident = notification.resident; + hasActionIcons = notification.hasActionIcons; + actions = notification.actions.map(a => ({ + identifier: a.identifier, + text: a.text, + invoke: () => a.invoke() + })); + } + } + + Component { + id: notifComp + + Notif {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Backgrounds.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Backgrounds.qml new file mode 100644 index 0000000..bfe7549 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Backgrounds.qml @@ -0,0 +1,90 @@ +import Quickshell +import QtQuick +import QtQuick.Shapes +import qs.Modules as Modules +import qs.Modules.Notifications as Notifications +import qs.Modules.Notifications.Sidebar as Sidebar +import qs.Modules.Notifications.Sidebar.Utils as Utils +import qs.Modules.Dashboard as Dashboard +import qs.Modules.Osd as Osd +import qs.Modules.Launcher as Launcher +import qs.Modules.Settings as Settings + +Shape { + id: root + + required property Panels panels + required property Item bar + required property PersistentProperties visibilities + + anchors.fill: parent + // anchors.margins: 8 + anchors.topMargin: bar.implicitHeight + preferredRendererType: Shape.CurveRenderer + + Component.onCompleted: console.log(root.bar.implicitHeight, root.bar.anchors.topMargin) + + Osd.Background { + wrapper: root.panels.osd + + startX: root.width - root.panels.sidebar.width + startY: ( root.height - wrapper.height ) / 2 - rounding + } + + Modules.Background { + wrapper: root.panels.popouts + invertBottomRounding: wrapper.x <= 0 + + startX: wrapper.x - 8 + startY: wrapper.y + } + + Notifications.Background { + wrapper: root.panels.notifications + sidebar: sidebar + + startX: root.width + startY: 0 + } + + Launcher.Background { + wrapper: root.panels.launcher + + startX: ( root.width - wrapper.width ) / 2 - rounding + startY: root.height + } + + Dashboard.Background { + wrapper: root.panels.dashboard + + startX: root.width - root.panels.dashboard.width - rounding + startY: 0 + } + + Utils.Background { + wrapper: root.panels.utilities + sidebar: sidebar + + startX: root.width + startY: root.height + } + + Sidebar.Background { + id: sidebar + + wrapper: root.panels.sidebar + panels: root.panels + + startX: root.width + startY: root.panels.notifications.height + } + + Settings.Background { + id: settings + + wrapper: root.panels.settings + + startX: ( root.width - wrapper.width ) / 2 - rounding + startY: 0 + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Bar.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Bar.qml new file mode 100644 index 0000000..d168e2f --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Bar.qml @@ -0,0 +1,198 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Effects +import Quickshell +import Quickshell.Wayland +import Quickshell.Hyprland +import qs.Daemons +import qs.Components +import qs.Modules +import qs.Modules.Bar +import qs.Config +import qs.Helpers +import qs.Drawers + +Variants { + model: Quickshell.screens + Scope { + id: scope + required property var modelData + PanelWindow { + id: bar + property bool trayMenuVisible: false + screen: scope.modelData + color: "transparent" + property var root: Quickshell.shellDir + + WlrLayershell.namespace: "ZShell-Bar" + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.sidebar || visibilities.dashboard ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None + + contentItem.focus: true + + contentItem.Keys.onEscapePressed: { + if ( Config.barConfig.autoHide ) + visibilities.bar = false; + visibilities.sidebar = false; + visibilities.dashboard = false; + visibilities.osd = false; + } + + PanelWindow { + id: exclusionZone + WlrLayershell.namespace: "ZShell-Bar-Exclusion" + screen: bar.screen + WlrLayershell.layer: WlrLayer.Bottom + WlrLayershell.exclusionMode: Config.barConfig.autoHide ? ExclusionMode.Ignore : ExclusionMode.Auto + anchors { + left: true + right: true + top: true + } + color: "transparent" + implicitHeight: 34 + } + + anchors { + top: true + left: true + right: true + bottom: true + } + + mask: Region { + id: region + x: 0 + y: Config.barConfig.autoHide && !visibilities.bar ? 4 : 34 + + property list nullRegions: [] + + width: bar.width + height: bar.screen.height - backgroundRect.implicitHeight + intersection: Intersection.Xor + + regions: popoutRegions.instances + } + + Variants { + id: popoutRegions + model: panels.children + + Region { + required property Item modelData + + x: modelData.x + y: modelData.y + backgroundRect.implicitHeight + width: modelData.width + height: modelData.height + intersection: Intersection.Subtract + } + } + + HyprlandFocusGrab { + id: focusGrab + + active: visibilities.launcher || visibilities.sidebar || visibilities.dashboard || ( panels.popouts.hasCurrent && panels.popouts.currentName.startsWith( "traymenu" )) + windows: [bar] + onCleared: { + visibilities.launcher = false; + visibilities.sidebar = false; + visibilities.dashboard = false; + visibilities.osd = false; + panels.popouts.hasCurrent = false; + } + } + + PersistentProperties { + id: visibilities + + property bool sidebar + property bool dashboard + property bool bar + property bool osd + property bool launcher + property bool notif: NotifServer.popups.length > 0 + property bool settings + + Component.onCompleted: Visibilities.load(scope.modelData, this) + } + + Binding { + target: visibilities + property: "bar" + value: visibilities.sidebar || visibilities.dashboard || visibilities.osd || visibilities.notif + when: Config.barConfig.autoHide + } + + Item { + anchors.fill: parent + opacity: Appearance.transparency.enabled ? DynamicColors.transparency.base : 1 + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + blurMax: 32 + shadowColor: Qt.alpha(DynamicColors.palette.m3shadow, 1) + } + + Border { + bar: backgroundRect + visibilities: visibilities + } + + Backgrounds { + visibilities: visibilities + panels: panels + bar: backgroundRect + } + } + + Interactions { + id: mouseArea + screen: scope.modelData + popouts: panels.popouts + visibilities: visibilities + panels: panels + bar: barLoader + anchors.fill: parent + + Panels { + id: panels + screen: scope.modelData + bar: backgroundRect + visibilities: visibilities + } + + CustomRect { + id: backgroundRect + property Wrapper popouts: panels.popouts + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: 34 + anchors.topMargin: Config.barConfig.autoHide && !visibilities.bar ? -30 : 0 + color: "transparent" + radius: 0 + + + Behavior on color { + CAnim {} + } + + Behavior on anchors.topMargin { + Anim {} + } + + BarLoader { + id: barLoader + anchors.fill: parent + popouts: panels.popouts + bar: bar + visibilities: visibilities + screen: scope.modelData + } + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Interactions.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Interactions.qml new file mode 100644 index 0000000..a8b3cad --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Interactions.qml @@ -0,0 +1,278 @@ +import Quickshell +import QtQuick +import qs.Components +import qs.Config +import qs.Modules as BarPopouts + +CustomMouseArea { + id: root + + required property ShellScreen screen + required property BarPopouts.Wrapper popouts + required property PersistentProperties visibilities + required property Panels panels + required property Item bar + + property point dragStart + property bool dashboardShortcutActive + property bool osdShortcutActive + property bool utilitiesShortcutActive + + function withinPanelHeight(panel: Item, x: real, y: real): bool { + const panelY = panel.y + bar.implicitHeight; + return y >= panelY && y <= panelY + panel.height; + } + + function withinPanelWidth(panel: Item, x: real, y: real): bool { + const panelX = panel.x; + return x >= panelX && x <= panelX + panel.width; + } + + function inLeftPanel(panel: Item, x: real, y: real): bool { + return x < panel.x + panel.width && withinPanelHeight(panel, x, y); + } + + function inRightPanel(panel: Item, x: real, y: real): bool { + return x > panel.x && withinPanelHeight(panel, x, y); + } + + function inTopPanel(panel: Item, x: real, y: real): bool { + return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y); + } + + function inBottomPanel(panel: Item, x: real, y: real): bool { + return y > root.height - panel.height && withinPanelWidth(panel, x, y); + } + + function onWheel(event: WheelEvent): void { + if (event.x < bar.implicitWidth) { + bar.handleWheel(event.y, event.angleDelta); + } + } + + anchors.fill: parent + hoverEnabled: true + + // onPressed: event => { + // if ( root.popouts.hasCurrent && !inTopPanel( root.popouts, event.x, event.y )) { + // root.popouts.hasCurrent = false; + // } else if (root.visibilities.sidebar && !inRightPanel( panels.sidebar, event.x, event.y )) { + // root.visibilities.sidebar = false; + // } else if (root.visibilities.dashboard && !inTopPanel( panels.dashboard, event.x, event.y )) { + // root.visibilities.dashboard = false; + // } + // } + + onContainsMouseChanged: { + if (!containsMouse) { + // Only hide if not activated by shortcut + if (!osdShortcutActive) { + visibilities.osd = false; + root.panels.osd.hovered = false; + } + + if (!popouts.currentName.startsWith("traymenu")) { + popouts.hasCurrent = false; + } + + if (Config.barConfig.autoHide && !root.visibilities.sidebar && !root.visibilities.dashboard) + root.visibilities.bar = false; + } + } + + onPositionChanged: event => { + if (popouts.isDetached) + return; + + const x = event.x; + const y = event.y; + const dragX = x - dragStart.x; + const dragY = y - dragStart.y; + + // Show bar in non-exclusive mode on hover + if (!visibilities.bar && Config.barConfig.autoHide && y < bar.implicitHeight + bar.anchors.topMargin) + visibilities.bar = true; + + if (panels.sidebar.width === 0) { + // Show osd on hover + const showOsd = inRightPanel(panels.osd, x, y); + + // // Always update visibility based on hover if not in shortcut mode + if (!osdShortcutActive) { + visibilities.osd = showOsd; + root.panels.osd.hovered = showOsd; + } else if (showOsd) { + // If hovering over OSD area while in shortcut mode, transition to hover control + osdShortcutActive = false; + root.panels.osd.hovered = true; + } + + // const showSidebar = pressed && dragStart.x > bar.implicitWidth + panels.sidebar.x; + // + // // Show/hide session on drag + // if (pressed && inRightPanel(panels.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) { + // if (dragX < -Config.session.dragThreshold) + // visibilities.session = true; + // else if (dragX > Config.session.dragThreshold) + // visibilities.session = false; + // + // // Show sidebar on drag if in session area and session is nearly fully visible + // if (showSidebar && panels.session.width >= panels.session.nonAnimWidth && dragX < -Config.sidebar.dragThreshold) + // visibilities.sidebar = true; + // } else if (showSidebar && dragX < -Config.sidebar.dragThreshold) { + // // Show sidebar on drag if not in session area + // visibilities.sidebar = true; + // } + } else { + const outOfSidebar = x < width - panels.sidebar.width; + // Show osd on hover + const showOsd = outOfSidebar && inRightPanel(panels.osd, x, y); + + // Always update visibility based on hover if not in shortcut mode + if (!osdShortcutActive) { + visibilities.osd = showOsd; + root.panels.osd.hovered = showOsd; + } else if (showOsd) { + // If hovering over OSD area while in shortcut mode, transition to hover control + osdShortcutActive = false; + root.panels.osd.hovered = true; + } + // + // // Show/hide session on drag + // if (pressed && outOfSidebar && inRightPanel(panels.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) { + // if (dragX < -Config.session.dragThreshold) + // visibilities.session = true; + // else if (dragX > Config.session.dragThreshold) + // visibilities.session = false; + // } + // + // // Hide sidebar on drag + // if (pressed && inRightPanel(panels.sidebar, dragStart.x, 0) && dragX > Config.sidebar.dragThreshold) + // visibilities.sidebar = false; + } + + // Show launcher on hover, or show/hide on drag if hover is disabled + // if (Config.launcher.showOnHover) { + // if (!visibilities.launcher && inBottomPanel(panels.launcher, x, y)) + // visibilities.launcher = true; + // } else if (pressed && inBottomPanel(panels.launcher, dragStart.x, dragStart.y) && withinPanelWidth(panels.launcher, x, y)) { + // if (dragY < -Config.launcher.dragThreshold) + // visibilities.launcher = true; + // else if (dragY > Config.launcher.dragThreshold) + // visibilities.launcher = false; + // } + // + // // Show dashboard on hover + // const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboard, x, y); + // + // // Always update visibility based on hover if not in shortcut mode + // if (!dashboardShortcutActive) { + // visibilities.dashboard = showDashboard; + // } else if (showDashboard) { + // // If hovering over dashboard area while in shortcut mode, transition to hover control + // dashboardShortcutActive = false; + // } + // + // // Show/hide dashboard on drag (for touchscreen devices) + // if (pressed && inTopPanel(panels.dashboard, dragStart.x, dragStart.y) && withinPanelWidth(panels.dashboard, x, y)) { + // if (dragY > Config.dashboard.dragThreshold) + // visibilities.dashboard = true; + // else if (dragY < -Config.dashboard.dragThreshold) + // visibilities.dashboard = false; + // } + // + // // Show utilities on hover + // const showUtilities = inBottomPanel(panels.utilities, x, y); + // + // // Always update visibility based on hover if not in shortcut mode + // if (!utilitiesShortcutActive) { + // visibilities.utilities = showUtilities; + // } else if (showUtilities) { + // // If hovering over utilities area while in shortcut mode, transition to hover control + // utilitiesShortcutActive = false; + // } + + // Show popouts on hover + if (y < bar.implicitHeight) { + bar.checkPopout(x); + } + } + + // Monitor individual visibility changes + Connections { + target: root.visibilities + + function onLauncherChanged() { + // If launcher is hidden, clear shortcut flags for dashboard and OSD + if (!root.visibilities.launcher) { + root.dashboardShortcutActive = false; + root.osdShortcutActive = false; + root.utilitiesShortcutActive = false; + + // Also hide dashboard and OSD if they're not being hovered + const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY); + const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); + + if (!inDashboardArea) { + root.visibilities.dashboard = false; + } + if (!inOsdArea) { + root.visibilities.osd = false; + root.panels.osd.hovered = false; + } + } + } + + function onSidebarChanged() { + if ( root.visibilities.sidebar ) { + root.visibilities.dashboard = false; + root.popouts.hasCurrent = false; + } + } + + function onDashboardChanged() { + if (root.visibilities.dashboard) { + // Dashboard became visible, immediately check if this should be shortcut mode + const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY); + if (!inDashboardArea) { + root.dashboardShortcutActive = true; + } + + root.visibilities.sidebar = false; + root.popouts.hasCurrent = false; + + } else { + // Dashboard hidden, clear shortcut flag + root.dashboardShortcutActive = false; + // root.visibilities.bar = false; + } + } + + function onOsdChanged() { + if (root.visibilities.osd) { + // OSD became visible, immediately check if this should be shortcut mode + const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); + console.log(inOsdArea); + if (!inOsdArea) { + root.osdShortcutActive = true; + } + } else { + // OSD hidden, clear shortcut flag + root.osdShortcutActive = false; + } + } + + function onUtilitiesChanged() { + if (root.visibilities.utilities) { + // Utilities became visible, immediately check if this should be shortcut mode + const inUtilitiesArea = root.inBottomPanel(root.panels.utilities, root.mouseX, root.mouseY); + if (!inUtilitiesArea) { + root.utilitiesShortcutActive = true; + } + } else { + // Utilities hidden, clear shortcut flag + root.utilitiesShortcutActive = false; + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Panels.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Panels.qml new file mode 100644 index 0000000..641fef4 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Drawers/Panels.qml @@ -0,0 +1,136 @@ +import Quickshell +import QtQuick +import qs.Components +import qs.Modules as Modules +import qs.Modules.Notifications as Notifications +import qs.Modules.Notifications.Sidebar as Sidebar +import qs.Modules.Notifications.Sidebar.Utils as Utils +import qs.Modules.Dashboard as Dashboard +import qs.Modules.Osd as Osd +import qs.Components.Toast as Toasts +import qs.Modules.Launcher as Launcher +import qs.Modules.Settings as Settings +import qs.Config + +Item { + id: root + + required property ShellScreen screen + required property Item bar + required property PersistentProperties visibilities + + readonly property alias popouts: popouts + readonly property alias sidebar: sidebar + readonly property alias notifications: notifications + readonly property alias utilities: utilities + readonly property alias dashboard: dashboard + readonly property alias osd: osd + readonly property alias toasts: toasts + readonly property alias launcher: launcher + readonly property alias settings: settings + + anchors.fill: parent + // anchors.margins: 8 + anchors.topMargin: Config.barConfig.autoHide && !visibilities.bar ? 0 : bar.implicitHeight + Behavior on anchors.topMargin { + Anim {} + } + + Osd.Wrapper { + id: osd + + clip: sidebar.width > 0 + screen: root.screen + visibilities: root.visibilities + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: sidebar.width + } + + Modules.Wrapper { + id: popouts + + screen: root.screen + + anchors.top: parent.top + + x: { + const off = currentCenter - nonAnimWidth / 2; + const diff = root.width - Math.floor(off + nonAnimWidth); + if ( diff < 0 ) + return off + diff; + return Math.floor( Math.max( off, 0 )); + } + } + + Toasts.Toasts { + id: toasts + + anchors.bottom: sidebar.visible ? parent.bottom : utilities.top + anchors.right: sidebar.left + anchors.margins: Appearance.padding.normal + } + + Notifications.Wrapper { + id: notifications + + visibilities: root.visibilities + panels: root + + anchors.top: parent.top + anchors.right: parent.right + } + + Launcher.Wrapper { + id: launcher + + screen: root.screen + visibilities: root.visibilities + panels: root + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + } + + Utils.Wrapper { + id: utilities + + visibilities: root.visibilities + sidebar: sidebar + popouts: popouts + + anchors.bottom: parent.bottom + anchors.right: parent.right + } + + Dashboard.Wrapper { + id: dashboard + + visibilities: root.visibilities + + anchors.right: parent.right + anchors.top: parent.top + } + + Sidebar.Wrapper { + id: sidebar + + visibilities: root.visibilities + panels: root + + anchors.top: notifications.bottom + anchors.bottom: utilities.top + anchors.right: parent.right + } + + Settings.Wrapper { + id: settings + + visibilities: root.visibilities + panels: root + + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Effects/ShadowRect.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Effects/ShadowRect.qml new file mode 100644 index 0000000..92889c4 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Effects/ShadowRect.qml @@ -0,0 +1,30 @@ +import QtQuick +import QtQuick.Effects + +Item { + id: root + property real radius + + Rectangle { + id: shadowRect + anchors.fill: root + radius: root.radius + layer.enabled: true + color: "black" + visible: false + } + + MultiEffect { + id: effects + source: shadowRect + anchors.fill: shadowRect + shadowBlur: 2.0 + shadowEnabled: true + shadowOpacity: 1 + shadowColor: "black" + maskSource: shadowRect + maskEnabled: true + maskInverted: true + autoPaddingEnabled: true + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/AreaPicker.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/AreaPicker.qml new file mode 100644 index 0000000..d329829 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/AreaPicker.qml @@ -0,0 +1,84 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Wayland +import Quickshell.Io +import Quickshell.Hyprland +import ZShell +import qs.Components + +Scope { + LazyLoader { + id: root + + property bool freeze + property bool closing + + Variants { + model: Quickshell.screens + PanelWindow { + id: win + color: "transparent" + + required property ShellScreen modelData + + screen: modelData + WlrLayershell.namespace: "areapicker" + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.keyboardFocus: root.closing ? WlrKeyboardFocus.None : WlrKeyboardFocus.Exclusive + mask: root.closing ? empty : null + + anchors { + top: true + bottom: true + left: true + right: true + } + + Region { + id: empty + } + + Picker { + loader: root + screen: win.modelData + } + } + } + } + + IpcHandler { + target: "picker" + + function open(): void { + root.freeze = false; + root.closing = false; + root.activeAsync = true; + } + + function openFreeze(): void { + root.freeze = true; + root.closing = false; + root.activeAsync = true; + } + } + + CustomShortcut { + name: "screenshot" + onPressed: { + root.freeze = false; + root.closing = false; + root.activeAsync = true; + } + } + + CustomShortcut { + name: "screenshotFreeze" + onPressed: { + root.freeze = true; + root.closing = false; + root.activeAsync = true; + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Brightness.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Brightness.qml new file mode 100644 index 0000000..becd1bc --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Brightness.qml @@ -0,0 +1,226 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import QtQuick +import qs.Config +import qs.Components + +Singleton { + id: root + + property list ddcMonitors: [] + readonly property list monitors: variants.instances + property bool appleDisplayPresent: false + + function getMonitorForScreen(screen: ShellScreen): var { + return monitors.find(m => m.modelData === screen); + } + + function getMonitor(query: string): var { + if (query === "active") { + return monitors.find(m => Hypr.monitorFor(m.modelData)?.focused); + } + + if (query.startsWith("model:")) { + const model = query.slice(6); + return monitors.find(m => m.modelData.model === model); + } + + if (query.startsWith("serial:")) { + const serial = query.slice(7); + return monitors.find(m => m.modelData.serialNumber === serial); + } + + if (query.startsWith("id:")) { + const id = parseInt(query.slice(3), 10); + return monitors.find(m => Hypr.monitorFor(m.modelData)?.id === id); + } + + return monitors.find(m => m.modelData.name === query); + } + + function increaseBrightness(): void { + const monitor = getMonitor("active"); + if (monitor) + monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement); + } + + function decreaseBrightness(): void { + const monitor = getMonitor("active"); + if (monitor) + monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); + } + + onMonitorsChanged: { + ddcMonitors = []; + ddcProc.running = true; + } + + Variants { + id: variants + + model: Quickshell.screens + + Monitor {} + } + + Process { + running: true + command: ["sh", "-c", "asdbctl get"] // To avoid warnings if asdbctl is not installed + stdout: StdioCollector { + onStreamFinished: root.appleDisplayPresent = text.trim().length > 0 + } + } + + Process { + id: ddcProc + + command: ["ddcutil", "detect", "--brief"] + stdout: StdioCollector { + onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({ + busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1], + connector: d.match(/DRM connector:\s+(.*)/)[1].replace(/^card\d+-/, "") // strip "card1-" + })) + } + } + + CustomShortcut { + name: "brightnessUp" + description: "Increase brightness" + onPressed: root.increaseBrightness() + } + + CustomShortcut { + name: "brightnessDown" + description: "Decrease brightness" + onPressed: root.decreaseBrightness() + } + + IpcHandler { + target: "brightness" + + function get(): real { + return getFor("active"); + } + + // Allows searching by active/model/serial/id/name + function getFor(query: string): real { + return root.getMonitor(query)?.brightness ?? -1; + } + + function set(value: string): string { + return setFor("active", value); + } + + // Handles brightness value like brightnessctl: 0.1, +0.1, 0.1-, 10%, +10%, 10%- + function setFor(query: string, value: string): string { + const monitor = root.getMonitor(query); + if (!monitor) + return "Invalid monitor: " + query; + + let targetBrightness; + if (value.endsWith("%-")) { + const percent = parseFloat(value.slice(0, -2)); + targetBrightness = monitor.brightness - (percent / 100); + } else if (value.startsWith("+") && value.endsWith("%")) { + const percent = parseFloat(value.slice(1, -1)); + targetBrightness = monitor.brightness + (percent / 100); + } else if (value.endsWith("%")) { + const percent = parseFloat(value.slice(0, -1)); + targetBrightness = percent / 100; + } else if (value.startsWith("+")) { + const increment = parseFloat(value.slice(1)); + targetBrightness = monitor.brightness + increment; + } else if (value.endsWith("-")) { + const decrement = parseFloat(value.slice(0, -1)); + targetBrightness = monitor.brightness - decrement; + } else if (value.includes("%") || value.includes("-") || value.includes("+")) { + return `Invalid brightness format: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`; + } else { + targetBrightness = parseFloat(value); + } + + if (isNaN(targetBrightness)) + return `Failed to parse value: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`; + + monitor.setBrightness(targetBrightness); + + return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`; + } + } + + component Monitor: QtObject { + id: monitor + + required property ShellScreen modelData + readonly property bool isDdc: root.ddcMonitors.some(m => m.connector === modelData.name) + readonly property string busNum: root.ddcMonitors.find(m => m.connector === modelData.name)?.busNum ?? "" + readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay") + property real brightness + property real queuedBrightness: NaN + + readonly property Process initProc: Process { + stdout: StdioCollector { + onStreamFinished: { + if (monitor.isAppleDisplay) { + const val = parseInt(text.trim()); + monitor.brightness = val / 101; + } else { + const [, , , cur, max] = text.split(" "); + monitor.brightness = parseInt(cur) / parseInt(max); + } + } + } + } + + readonly property Timer timer: Timer { + interval: 500 + onTriggered: { + if (!isNaN(monitor.queuedBrightness)) { + monitor.setBrightness(monitor.queuedBrightness); + monitor.queuedBrightness = NaN; + } + } + } + + function setBrightness(value: real): void { + value = Math.max(0, Math.min(1, value)); + const rounded = Math.round(value * 100); + if (Math.round(brightness * 100) === rounded) + return; + + if (isDdc && timer.running) { + queuedBrightness = value; + return; + } + + brightness = value; + + if (isAppleDisplay) + Quickshell.execDetached(["asdbctl", "set", rounded]); + else if (isDdc) + Quickshell.execDetached(["ddcutil", "--disable-dynamic-sleep", "--sleep-multiplier", ".1", "--skip-ddc-checks", "-b", busNum, "setvcp", "10", rounded]); + else + Quickshell.execDetached(["brightnessctl", "s", `${rounded}%`]); + + if (isDdc) + timer.restart(); + } + + function initBrightness(): void { + if (isAppleDisplay) + initProc.command = ["asdbctl", "get"]; + else if (isDdc) + initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"]; + else + initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"]; + + initProc.running = true; + } + + onBusNumChanged: initBrightness() + Component.onCompleted: initBrightness() + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/CachingImage.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/CachingImage.qml new file mode 100644 index 0000000..905349b --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/CachingImage.qml @@ -0,0 +1,28 @@ +import ZShell.Internal +import Quickshell +import QtQuick +import qs.Paths + +Image { + id: root + + property alias path: manager.path + + asynchronous: true + fillMode: Image.PreserveAspectCrop + + Connections { + target: QsWindow.window + + function onDevicePixelRatioChanged(): void { + manager.updateSource(); + } + } + + CachingImageManager { + id: manager + + item: root + cacheDir: Qt.resolvedUrl(Paths.imagecache) + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Calendar.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Calendar.qml new file mode 100644 index 0000000..585d93a --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Calendar.qml @@ -0,0 +1,99 @@ +pragma Singleton + +import Quickshell +import qs.Helpers + +Singleton { + id: root + + property int displayMonth: new Date().getMonth() + property int displayYear: new Date().getFullYear() + readonly property int weekStartDay: 1 // 0 = Sunday, 1 = Monday + + function getWeeksForMonth(month: int, year: int): var { + const firstDayOfMonth = new Date(year, month, 1); + const lastDayOfMonth = new Date(year, month + 1, 0); + + const days = []; + let currentDate = new Date(year, month, 1); + + // Back up to the start of the first week (Sunday or Monday based on locale) + const dayOfWeek = firstDayOfMonth.getDay(); + const daysToBackup = (dayOfWeek - root.weekStartDay + 7) % 7; + currentDate.setDate(currentDate.getDate() - daysToBackup); + + // Collect all days, including padding from previous/next month to complete the weeks + while (true) { + days.push({ + day: currentDate.getDate(), + month: currentDate.getMonth(), + year: currentDate.getFullYear(), + isCurrentMonth: currentDate.getMonth() === month, + isToday: isDateToday(currentDate) + }); + + currentDate.setDate(currentDate.getDate() + 1); + + // Stop after we've completed a full week following the last day of the month + if (currentDate > lastDayOfMonth && days.length % 7 === 0) { + break; + } + } + + return days; + } + + function getWeekNumbers(month: int, year: int): var { + const days = getWeeksForMonth(month, year); + const weekNumbers = []; + let lastWeekNumber = -1; + + for (let i = 0; i < days.length; i++) { + // Only add week numbers for days that belong to the current month + if (days[i].isCurrentMonth) { + const dayDate = new Date(days[i].year, days[i].month, days[i].day); + const weekNumber = getISOWeekNumber(dayDate); + + // Only push if this is a new week + if (weekNumber !== lastWeekNumber) { + weekNumbers.push(weekNumber); + lastWeekNumber = weekNumber; + } + } + } + + return weekNumbers; + } + + function getISOWeekNumber(date: var): int { + const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())); + const dayNum = d.getUTCDay() || 7; + d.setUTCDate(d.getUTCDate() + 4 - dayNum); + const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); + return Math.ceil((((d - yearStart) / 86400000) + 1) / 7); + } + + function isDateToday(date: var): bool { + const today = new Date(); + return date.getDate() === today.getDate() && + date.getMonth() === today.getMonth() && + date.getFullYear() === today.getFullYear(); + } + + function getWeekStartIndex(month: int, year: int): int { + const today = new Date(); + if (today.getMonth() !== month || today.getFullYear() !== year) { + return 0; + } + + const days = getWeeksForMonth(month, year); + for (let i = 0; i < days.length; i++) { + if (days[i].isToday) { + // Return the start index of the week containing today + return Math.floor(i / 7) * 7; + } + } + + return 0; + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/GetIcons.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/GetIcons.qml new file mode 100644 index 0000000..46cc993 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/GetIcons.qml @@ -0,0 +1,17 @@ +pragma Singleton + +import Quickshell + +Singleton { + id: root + + function getTrayIcon(id: string, icon: string): string { + if (icon.includes("?path=")) { + const [name, path] = icon.split("?path="); + icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`); + } else if (icon.includes("qspixmap") && id === "chrome_status_icon_1") { + icon = icon.replace("qspixmap", "icon/discord-tray"); + } + return icon; + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/HasNotifications.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/HasNotifications.qml new file mode 100644 index 0000000..5479858 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/HasNotifications.qml @@ -0,0 +1,15 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io + +Singleton { + id: root + + property alias hasNotifications: adapter.hasNotifications + + JsonObject { + id: adapter + property bool hasNotifications: false + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Hypr.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Hypr.qml new file mode 100644 index 0000000..0cab428 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Hypr.qml @@ -0,0 +1,165 @@ +pragma Singleton + +import ZShell +import ZShell.Internal +import Quickshell +import Quickshell.Hyprland +import Quickshell.Io +import QtQuick +import qs.Components + +Singleton { + id: root + + readonly property var toplevels: Hyprland.toplevels + readonly property var workspaces: Hyprland.workspaces + readonly property var monitors: Hyprland.monitors + + readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel + readonly property HyprlandWorkspace focusedWorkspace: Hyprland.focusedWorkspace + readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor + readonly property int activeWsId: focusedWorkspace?.id ?? 1 + + property string activeName + property string applicationDir: "/usr/share/applications/" + property string desktopName: "" + + readonly property HyprKeyboard keyboard: extras.devices.keyboards.find(kb => kb.main) ?? null + readonly property bool capsLock: keyboard?.capsLock ?? false + readonly property bool numLock: keyboard?.numLock ?? false + readonly property string defaultKbLayout: keyboard?.layout.split(",")[0] ?? "??" + readonly property string kbLayoutFull: keyboard?.activeKeymap ?? "Unknown" + readonly property string kbLayout: kbMap.get(kbLayoutFull) ?? "??" + readonly property var kbMap: new Map() + + readonly property alias extras: extras + readonly property alias options: extras.options + readonly property alias devices: extras.devices + + property bool hadKeyboard + + signal configReloaded + + function getActiveScreen(): ShellScreen { + return Quickshell.screens.find(screen => root.monitorFor(screen) === root.focusedMonitor) + } + + function dispatch(request: string): void { + Hyprland.dispatch(request); + } + + function monitorFor(screen: ShellScreen): HyprlandMonitor { + return Hyprland.monitorFor(screen); + } + + function reloadDynamicConfs(): void { + extras.batchMessage(["keyword bindlni ,Caps_Lock,global,zshell:refreshDevices", "keyword bindlni ,Num_Lock,global,zshell:refreshDevices"]); + } + + Component.onCompleted: reloadDynamicConfs() + + // function updateActiveWindow(): void { + // root.desktopName = root.applicationDir + root.activeToplevel?.lastIpcObject.class + ".desktop"; + // } + + Connections { + target: Hyprland + + function onRawEvent(event: HyprlandEvent): void { + const n = event.name; + if (n.endsWith("v2")) + return; + + if (n === "configreloaded") { + root.configReloaded(); + root.reloadDynamicConfs(); + } else if (["workspace", "moveworkspace", "activespecial", "focusedmon"].includes(n)) { + Hyprland.refreshWorkspaces(); + Hyprland.refreshMonitors(); + // Qt.callLater( root.updateActiveWindow ); + } else if (["openwindow", "closewindow", "movewindow"].includes(n)) { + Hyprland.refreshToplevels(); + Hyprland.refreshWorkspaces(); + // Qt.callLater( root.updateActiveWindow ); + } else if (n.includes("mon")) { + Hyprland.refreshMonitors(); + // Qt.callLater( root.updateActiveWindow ); + } else if (n.includes("workspace")) { + Hyprland.refreshWorkspaces(); + // Qt.callLater( root.updateActiveWindow ); + } else if (n.includes("window") || n.includes("group") || ["pin", "fullscreen", "changefloatingmode", "minimize"].includes(n)) { + Hyprland.refreshToplevels(); + // Qt.callLater( root.updateActiveWindow ); + } + } + } + + FileView { + id: desktopEntryName + + path: root.desktopName + + onLoaded: { + const lines = text().split( "\n" ); + for ( const line of lines ) { + if ( line.startsWith( "Name=" )) { + let name = line.replace( "Name=", "" ); + let caseFix = name[ 0 ].toUpperCase() + name.slice( 1 ); + root.activeName = caseFix; + break; + } + } + } + } + + FileView { + id: kbLayoutFile + + path: Quickshell.env("ZSHELL_XKB_RULES_PATH") || "/usr/share/X11/xkb/rules/base.lst" + onLoaded: { + const layoutMatch = text().match(/! layout\n([\s\S]*?)\n\n/); + if (layoutMatch) { + const lines = layoutMatch[1].split("\n"); + for (const line of lines) { + if (!line.trim() || line.trim().startsWith("!")) + continue; + + const match = line.match(/^\s*([a-z]{2,})\s+([a-zA-Z() ]+)$/); + if (match) + root.kbMap.set(match[2], match[1]); + } + } + + const variantMatch = text().match(/! variant\n([\s\S]*?)\n\n/); + if (variantMatch) { + const lines = variantMatch[1].split("\n"); + for (const line of lines) { + if (!line.trim() || line.trim().startsWith("!")) + continue; + + const match = line.match(/^\s*([a-zA-Z0-9_-]+)\s+([a-z]{2,}): (.+)$/); + if (match) + root.kbMap.set(match[3], match[2]); + } + } + } + } + + IpcHandler { + target: "hypr" + + function refreshDevices(): void { + extras.refreshDevices(); + } + } + + CustomShortcut { + name: "refreshDevices" + onPressed: extras.refreshDevices() + onReleased: extras.refreshDevices() + } + + HyprExtras { + id: extras + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Icons.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Icons.qml new file mode 100644 index 0000000..9524055 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Icons.qml @@ -0,0 +1,187 @@ +pragma Singleton + +import qs.Config +import Quickshell +import Quickshell.Services.Notifications +import QtQuick + +Singleton { + id: root + + readonly property var weatherIcons: ({ + "0": "clear_day", + "1": "clear_day", + "2": "partly_cloudy_day", + "3": "cloud", + "45": "foggy", + "48": "foggy", + "51": "rainy", + "53": "rainy", + "55": "rainy", + "56": "rainy", + "57": "rainy", + "61": "rainy", + "63": "rainy", + "65": "rainy", + "66": "rainy", + "67": "rainy", + "71": "cloudy_snowing", + "73": "cloudy_snowing", + "75": "snowing_heavy", + "77": "cloudy_snowing", + "80": "rainy", + "81": "rainy", + "82": "rainy", + "85": "cloudy_snowing", + "86": "snowing_heavy", + "95": "thunderstorm", + "96": "thunderstorm", + "99": "thunderstorm" + }) + + readonly property var categoryIcons: ({ + WebBrowser: "web", + Printing: "print", + Security: "security", + Network: "chat", + Archiving: "archive", + Compression: "archive", + Development: "code", + IDE: "code", + TextEditor: "edit_note", + Audio: "music_note", + Music: "music_note", + Player: "music_note", + Recorder: "mic", + Game: "sports_esports", + FileTools: "files", + FileManager: "files", + Filesystem: "files", + FileTransfer: "files", + Settings: "settings", + DesktopSettings: "settings", + HardwareSettings: "settings", + TerminalEmulator: "terminal", + ConsoleOnly: "terminal", + Utility: "build", + Monitor: "monitor_heart", + Midi: "graphic_eq", + Mixer: "graphic_eq", + AudioVideoEditing: "video_settings", + AudioVideo: "music_video", + Video: "videocam", + Building: "construction", + Graphics: "photo_library", + "2DGraphics": "photo_library", + RasterGraphics: "photo_library", + TV: "tv", + System: "host", + Office: "content_paste" + }) + + function getAppIcon(name: string, fallback: string): string { + const icon = DesktopEntries.heuristicLookup(name)?.icon; + if (fallback !== "undefined") + return Quickshell.iconPath(icon, fallback); + return Quickshell.iconPath(icon); + } + + function getAppCategoryIcon(name: string, fallback: string): string { + const categories = DesktopEntries.heuristicLookup(name)?.categories; + + if (categories) + for (const [key, value] of Object.entries(categoryIcons)) + if (categories.includes(key)) + return value; + return fallback; + } + + function getNetworkIcon(strength: int, isSecure = false): string { + if (isSecure) { + if (strength >= 80) + return "network_wifi_locked"; + if (strength >= 60) + return "network_wifi_3_bar_locked"; + if (strength >= 40) + return "network_wifi_2_bar_locked"; + if (strength >= 20) + return "network_wifi_1_bar_locked"; + return "signal_wifi_0_bar"; + } else { + if (strength >= 80) + return "network_wifi"; + if (strength >= 60) + return "network_wifi_3_bar"; + if (strength >= 40) + return "network_wifi_2_bar"; + if (strength >= 20) + return "network_wifi_1_bar"; + return "signal_wifi_0_bar"; + } + } + + function getBluetoothIcon(icon: string): string { + if (icon.includes("headset") || icon.includes("headphones")) + return "headphones"; + if (icon.includes("audio")) + return "speaker"; + if (icon.includes("phone")) + return "smartphone"; + if (icon.includes("mouse")) + return "mouse"; + if (icon.includes("keyboard")) + return "keyboard"; + return "bluetooth"; + } + + function getWeatherIcon(code: string): string { + if (weatherIcons.hasOwnProperty(code)) + return weatherIcons[code]; + return "air"; + } + + function getNotifIcon(summary: string, urgency: int): string { + summary = summary.toLowerCase(); + if (summary.includes("reboot")) + return "restart_alt"; + if (summary.includes("recording")) + return "screen_record"; + if (summary.includes("battery")) + return "power"; + if (summary.includes("screenshot")) + return "screenshot_monitor"; + if (summary.includes("welcome")) + return "waving_hand"; + if (summary.includes("time") || summary.includes("a break")) + return "schedule"; + if (summary.includes("installed")) + return "download"; + if (summary.includes("update")) + return "update"; + if (summary.includes("unable to")) + return "deployed_code_alert"; + if (summary.includes("profile")) + return "person"; + if (summary.includes("file")) + return "folder_copy"; + if (urgency === NotificationUrgency.Critical) + return "release_alert"; + return "chat"; + } + + function getVolumeIcon(volume: real, isMuted: bool): string { + if (isMuted) + return "no_sound"; + if (volume >= 0.5) + return "volume_up"; + if (volume > 0) + return "volume_down"; + return "volume_mute"; + } + + function getMicVolumeIcon(volume: real, isMuted: bool): string { + if (!isMuted && volume > 0) + return "mic"; + return "mic_off"; + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/IdleInhibitor.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/IdleInhibitor.qml new file mode 100644 index 0000000..29409ab --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/IdleInhibitor.qml @@ -0,0 +1,56 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import Quickshell.Wayland + +Singleton { + id: root + + property alias enabled: props.enabled + readonly property alias enabledSince: props.enabledSince + + onEnabledChanged: { + if (enabled) + props.enabledSince = new Date(); + } + + PersistentProperties { + id: props + + property bool enabled + property date enabledSince + + reloadableId: "idleInhibitor" + } + + IdleInhibitor { + enabled: props.enabled + window: PanelWindow { + implicitWidth: 0 + implicitHeight: 0 + color: "transparent" + mask: Region {} + } + } + + IpcHandler { + target: "idleInhibitor" + + function isEnabled(): bool { + return props.enabled; + } + + function toggle(): void { + props.enabled = !props.enabled; + } + + function enable(): void { + props.enabled = true; + } + + function disable(): void { + props.enabled = false; + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/InitialTitle.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/InitialTitle.qml new file mode 100644 index 0000000..e169991 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/InitialTitle.qml @@ -0,0 +1,18 @@ +pragma Singleton + +import Quickshell +import Quickshell.Hyprland +import qs.Helpers + +Singleton { + function getInitialTitle(callback) { + let activeWindow = Hypr.activeToplevel.title + let activeClass = Hypr.activeToplevel.lastIpcObject.class.toString() + let regex = new RegExp(activeClass, "i") + + console.log("ActiveWindow", activeWindow, "ActiveClass", activeClass, "Regex", regex) + + const evalTitle = activeWindow.match(regex) + callback(evalTitle) + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/ModeScheduler.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/ModeScheduler.qml new file mode 100644 index 0000000..bab9bf6 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/ModeScheduler.qml @@ -0,0 +1,86 @@ +pragma Singleton + +import Quickshell +import QtQuick +import qs.Modules +import qs.Helpers +import qs.Config +import qs.Paths + +Singleton { + id: root + + readonly property int darkStart: Config.general.color.scheduleDarkStart + readonly property int darkEnd: Config.general.color.scheduleDarkEnd + + Timer { + id: darkModeTimer + + interval: 5000 + + running: true + repeat: true + onTriggered: { + if ( darkStart === darkEnd ) + return; + var now = new Date(); + if ( now.getHours() >= darkStart || now.getHours() < darkEnd ) { + if ( DynamicColors.light ) + applyDarkMode(); + } else { + if ( !DynamicColors.light ) + applyLightMode(); + } + } + } + + function applyDarkMode() { + if ( Config.general.color.schemeGeneration ) { + Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${WallpaperPath.currentWallpaperPath}`, "--thumbnail-path", `${Paths.cache}/imagecache/thumbnail.jpg`, "--output", `${Paths.state}/scheme.json`, "--scheme", `${Config.colors.schemeType}`, "--mode", "dark"]); + } else { + Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${DynamicColors.scheme}:${DynamicColors.flavour}`, "--output", `${Paths.state}/scheme.json`, "--mode", "dark"]); + } + + Config.general.color.mode = "dark"; + + Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"]) + + Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Light.colors/color_scheme_path=\\1Dark.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]) + + Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"tokyodark\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]) + + if( Config.general.color.wallust ) + Wallust.generateColors(WallpaperPath.currentWallpaperPath); + } + + function applyLightMode() { + if ( Config.general.color.neovimColors ) { + Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${WallpaperPath.currentWallpaperPath}`, "--thumbnail-path", `${Paths.cache}/imagecache/thumbnail.jpg`, "--output", `${Paths.state}/scheme.json`, "--scheme", `${Config.colors.schemeType}`, "--mode", "light"]); + } else { + Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${DynamicColors.scheme}:${DynamicColors.flavour}`, "--output", `${Paths.state}/scheme.json`, "--mode", "light"]); + } + + Config.general.color.mode = "light"; + + Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"]) + + Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]) + + if ( Config.general.color.neovimColors ) + Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]) + + if( Config.general.color.wallust ) + Wallust.generateColors(WallpaperPath.currentWallpaperPath); + } + + function checkStartup() { + if ( darkStart === darkEnd ) + return; + var now = new Date(); + if ( now.getHours() >= darkStart || now.getHours() < darkEnd ) { + applyDarkMode(); + } else { + applyLightMode(); + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Network.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Network.qml new file mode 100644 index 0000000..7296f10 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Network.qml @@ -0,0 +1,11 @@ +pragma Singleton + +import Quickshell +import Quickshell.Networking + +Singleton { + id: root + + property list devices: Networking.devices.values + property NetworkDevice activeDevice: devices.find(d => d.connected) +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/NotifCenterSpacing.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/NotifCenterSpacing.qml new file mode 100644 index 0000000..e5b34ed --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/NotifCenterSpacing.qml @@ -0,0 +1,16 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io + +Singleton { + id: root + + property alias centerX: notifCenterSpacing.centerX + + JsonAdapter { + id: notifCenterSpacing + + property int centerX + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/NotifPath.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/NotifPath.qml new file mode 100644 index 0000000..3d4b3cd --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/NotifPath.qml @@ -0,0 +1,16 @@ +pragma Singleton + +import Quickshell.Io +import Quickshell + +Singleton { + id: root + + property alias notifPath: storage.notifPath + + JsonAdapter { + id: storage + + property string notifPath: Quickshell.statePath("notifications.json") + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Picker.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Picker.qml new file mode 100644 index 0000000..1878000 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Picker.qml @@ -0,0 +1,295 @@ +pragma ComponentBehavior: Bound + +import ZShell +import Quickshell +import Quickshell.Wayland +import QtQuick +import QtQuick.Effects +import qs.Components +import qs.Config +import qs.Helpers + +MouseArea { + id: root + + required property LazyLoader loader + required property ShellScreen screen + + property bool onClient + + property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2 + property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0 + + property real ssx + property real ssy + + property real sx: 0 + property real sy: 0 + property real ex: screen.width + property real ey: screen.height + + property real rsx: Math.min(sx, ex) + property real rsy: Math.min(sy, ey) + property real sw: Math.abs(sx - ex) + property real sh: Math.abs(sy - ey) + + property list clients: { + const mon = Hypr.monitorFor(screen); + if (!mon) + return []; + + const special = mon.lastIpcObject.specialWorkspace; + const wsId = special.name ? special.id : mon.activeWorkspace.id; + + return Hypr.toplevels.values.filter(c => c.workspace?.id === wsId).sort((a, b) => { + const ac = a.lastIpcObject; + const bc = b.lastIpcObject; + return (bc.pinned - ac.pinned) || ((bc.fullscreen !== 0) - (ac.fullscreen !== 0)) || (bc.floating - ac.floating); + }); + } + + function checkClientRects(x: real, y: real): void { + for (const client of clients) { + if (!client) + continue; + + let { + at: [cx, cy], + size: [cw, ch] + } = client.lastIpcObject; + cx -= screen.x; + cy -= screen.y; + if (cx <= x && cy <= y && cx + cw >= x && cy + ch >= y) { + onClient = true; + sx = cx; + sy = cy; + ex = cx + cw; + ey = cy + ch; + break; + } + } + } + + function save(): void { + const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`); + ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached(["swappy", "-f", path])); + closeAnim.start(); + } + + onClientsChanged: checkClientRects(mouseX, mouseY) + + anchors.fill: parent + opacity: 0 + hoverEnabled: true + cursorShape: Qt.CrossCursor + + Component.onCompleted: { + Hypr.extras.refreshOptions(); + if (loader.freeze) + clients = clients; + + opacity = 1; + + const c = clients[0]; + if (c) { + const cx = c.lastIpcObject.at[0] - screen.x; + const cy = c.lastIpcObject.at[1] - screen.y; + onClient = true; + sx = cx; + sy = cy; + ex = cx + c.lastIpcObject.size[0]; + ey = cy + c.lastIpcObject.size[1]; + } else { + sx = screen.width / 2 - 100; + sy = screen.height / 2 - 100; + ex = screen.width / 2 + 100; + ey = screen.height / 2 + 100; + } + } + + onPressed: event => { + ssx = event.x; + ssy = event.y; + } + + onReleased: { + if (closeAnim.running) + return; + + if (root.loader.freeze) { + save(); + } else { + overlay.visible = border.visible = false; + screencopy.visible = false; + screencopy.active = true; + } + } + + onPositionChanged: event => { + const x = event.x; + const y = event.y; + + if (pressed) { + onClient = false; + sx = ssx; + sy = ssy; + ex = x; + ey = y; + } else { + checkClientRects(x, y); + } + } + + focus: true + Keys.onEscapePressed: closeAnim.start() + + SequentialAnimation { + id: closeAnim + + PropertyAction { + target: root.loader + property: "closing" + value: true + } + ParallelAnimation { + Anim { + target: root + property: "opacity" + to: 0 + duration: 300 + } + ExAnim { + target: root + properties: "rsx,rsy" + to: 0 + } + ExAnim { + target: root + property: "sw" + to: root.screen.width + } + ExAnim { + target: root + property: "sh" + to: root.screen.height + } + } + PropertyAction { + target: root.loader + property: "activeAsync" + value: false + } + } + + Loader { + id: screencopy + + anchors.fill: parent + + active: root.loader.freeze + asynchronous: true + + sourceComponent: ScreencopyView { + captureSource: root.screen + + paintCursor: false + + onHasContentChanged: { + if (hasContent && !root.loader.freeze) { + overlay.visible = border.visible = true; + root.save(); + } + } + } + } + + Rectangle { + id: overlay + + anchors.fill: parent + color: "white" + opacity: 0.3 + + radius: root.realRounding + + layer.enabled: true + layer.effect: MultiEffect { + maskSource: selectionWrapper + maskEnabled: true + maskInverted: true + maskSpreadAtMin: 1 + maskThresholdMin: 0.5 + } + } + + Item { + id: selectionWrapper + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + id: selectionRect + + radius: root.realRounding + x: root.rsx + y: root.rsy + implicitWidth: root.sw + implicitHeight: root.sh + } + } + + Rectangle { + id: border + + color: "transparent" + radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0 + border.width: root.realBorderWidth + border.color: DynamicColors.palette.m3primary + + x: selectionRect.x - root.realBorderWidth + y: selectionRect.y - root.realBorderWidth + implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2 + implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2 + + Behavior on border.color { + Anim {} + } + } + + Behavior on opacity { + Anim { + duration: 300 + } + } + + Behavior on rsx { + enabled: !root.pressed + + ExAnim {} + } + + Behavior on rsy { + enabled: !root.pressed + + ExAnim {} + } + + Behavior on sw { + enabled: !root.pressed + + ExAnim {} + } + + Behavior on sh { + enabled: !root.pressed + + ExAnim {} + } + + component ExAnim: Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Players.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Players.qml new file mode 100644 index 0000000..a412849 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Players.qml @@ -0,0 +1,123 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import Quickshell.Services.Mpris +import QtQml +import ZShell +import qs.Config +import qs.Components + +Singleton { + id: root + + readonly property list list: Mpris.players.values + readonly property MprisPlayer active: props.manualActive ?? list.find(p => getIdentity(p) === Config.services.defaultPlayer) ?? list[0] ?? null + property alias manualActive: props.manualActive + + function getIdentity(player: MprisPlayer): string { + const alias = Config.services.playerAliases.find(a => a.from === player.identity); + return alias?.to ?? player.identity; + } + + Connections { + target: active + + function onPostTrackChanged() { + if (!Config.utilities.toasts.nowPlaying) { + return; + } + } + } + + PersistentProperties { + id: props + + property MprisPlayer manualActive + + reloadableId: "players" + } + + CustomShortcut { + name: "mediaToggle" + description: "Toggle media playback" + onPressed: { + const active = root.active; + if (active && active.canTogglePlaying) + active.togglePlaying(); + } + } + + CustomShortcut { + name: "mediaPrev" + description: "Previous track" + onPressed: { + const active = root.active; + if (active && active.canGoPrevious) + active.previous(); + } + } + + CustomShortcut { + name: "mediaNext" + description: "Next track" + onPressed: { + const active = root.active; + if (active && active.canGoNext) + active.next(); + } + } + + CustomShortcut { + name: "mediaStop" + description: "Stop media playback" + onPressed: root.active?.stop() + } + + IpcHandler { + target: "mpris" + + function getActive(prop: string): string { + const active = root.active; + return active ? active[prop] ?? "Invalid property" : "No active player"; + } + + function list(): string { + return root.list.map(p => root.getIdentity(p)).join("\n"); + } + + function play(): void { + const active = root.active; + if (active?.canPlay) + active.play(); + } + + function pause(): void { + const active = root.active; + if (active?.canPause) + active.pause(); + } + + function playPause(): void { + const active = root.active; + if (active?.canTogglePlaying) + active.togglePlaying(); + } + + function previous(): void { + const active = root.active; + if (active?.canGoPrevious) + active.previous(); + } + + function next(): void { + const active = root.active; + if (active?.canGoNext) + active.next(); + } + + function stop(): void { + root.active?.stop(); + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SearchWallpapers.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SearchWallpapers.qml new file mode 100644 index 0000000..1bbca74 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SearchWallpapers.qml @@ -0,0 +1,49 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import ZShell.Models +import qs.Config +import qs.Modules +import qs.Helpers +import qs.Paths + +Searcher { + id: root + + property bool showPreview: false + readonly property string current: showPreview ? previewPath : actualCurrent + property string previewPath + property string actualCurrent: WallpaperPath.currentWallpaperPath + + function setWallpaper(path: string): void { + actualCurrent = path; + WallpaperPath.currentWallpaperPath = path; + Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/LockScreenBg.py")} --input_image=${root.actualCurrent} --output_path=${Paths.state}/lockscreen_bg.png`]); + } + + function preview(path: string): void { + previewPath = path; + showPreview = true; + } + + function stopPreview(): void { + showPreview = false; + Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/SchemeColorGen.py")} --path=${root.actualCurrent} --thumbnail=${Paths.cache}/imagecache/thumbnail.jpg --output=${Paths.state}/scheme.json --scheme=${Config.colors.schemeType}`]); + } + + list: wallpapers.entries + key: "relativePath" + useFuzzy: true + extraOpts: useFuzzy ? ({}) : ({ + forward: false + }) + + FileSystemModel { + id: wallpapers + + recursive: true + path: Config.general.wallpaperPath + filter: FileSystemModel.Images + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Searcher.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Searcher.qml new file mode 100644 index 0000000..2a216dc --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Searcher.qml @@ -0,0 +1,55 @@ +import Quickshell +import "../scripts/fzf.js" as Fzf +import "../scripts/fuzzysort.js" as Fuzzy +import QtQuick + +Singleton { + required property list list + property string key: "name" + property bool useFuzzy: false + property var extraOpts: ({}) + + // Extra stuff for fuzzy + property list keys: [key] + property list weights: [1] + + readonly property var fzf: useFuzzy ? [] : new Fzf.Finder(list, Object.assign({ + selector + }, extraOpts)) + readonly property list fuzzyPrepped: useFuzzy ? list.map(e => { + const obj = { + _item: e + }; + for (const k of keys) + obj[k] = Fuzzy.prepare(e[k]); + return obj; + }) : [] + + function transformSearch(search: string): string { + return search; + } + + function selector(item: var): string { + // Only for fzf + return item[key]; + } + + function query(search: string): list { + search = transformSearch(search); + if (!search) + return [...list]; + + if (useFuzzy) + return Fuzzy.go(search, fuzzyPrepped, Object.assign({ + all: true, + keys, + scoreFn: r => weights.reduce((a, w, i) => a + r[i].score * w, 0) + }, extraOpts)).map(r => r.obj._item); + + return fzf.find(search).sort((a, b) => { + if (a.score === b.score) + return selector(a.item).trim().length - selector(b.item).trim().length; + return b.score - a.score; + }).map(r => r.item); + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SystemInfo.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SystemInfo.qml new file mode 100644 index 0000000..550a544 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SystemInfo.qml @@ -0,0 +1,84 @@ +pragma Singleton + +import qs.Config +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property string osName + property string osPrettyName + property string osId + property list osIdLike + property string osLogo + property bool isDefaultLogo: true + + property string uptime + readonly property string user: Quickshell.env("USER") + readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP") + readonly property string shell: Quickshell.env("SHELL").split("/").pop() + + FileView { + id: osRelease + + path: "/etc/os-release" + onLoaded: { + const lines = text().split("\n"); + + const fd = key => lines.find(l => l.startsWith(`${key}=`))?.split("=")[1].replace(/"/g, "") ?? ""; + + root.osName = fd("NAME"); + root.osPrettyName = fd("PRETTY_NAME"); + root.osId = fd("ID"); + root.osIdLike = fd("ID_LIKE").split(" "); + + const logo = Quickshell.iconPath(fd("LOGO"), true); + if (Config.general.logo) { + root.osLogo = Quickshell.iconPath(Config.general.logo, true) || "file://" + Paths.absolutePath(Config.general.logo); + root.isDefaultLogo = false; + } else if (logo) { + root.osLogo = logo; + root.isDefaultLogo = false; + } + } + } + + Connections { + target: Config.general + + function onLogoChanged(): void { + osRelease.reload(); + } + } + + Timer { + running: true + repeat: true + interval: 15000 + onTriggered: fileUptime.reload() + } + + FileView { + id: fileUptime + + path: "/proc/uptime" + onLoaded: { + const up = parseInt(text().split(" ")[0] ?? 0); + + const days = Math.floor(up / 86400); + const hours = Math.floor((up % 86400) / 3600); + const minutes = Math.floor((up % 3600) / 60); + + let str = ""; + if (days > 0) + str += `${days} day${days === 1 ? "" : "s"}`; + if (hours > 0) + str += `${str ? ", " : ""}${hours} hour${hours === 1 ? "" : "s"}`; + if (minutes > 0 || !str) + str += `${str ? ", " : ""}${minutes} minute${minutes === 1 ? "" : "s"}`; + root.uptime = str; + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SystemUsage.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SystemUsage.qml new file mode 100644 index 0000000..075545c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/SystemUsage.qml @@ -0,0 +1,237 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick +import qs.Config + +Singleton { + id: root + + property real cpuPerc + property real cpuTemp + readonly property string gpuType: Config.services.gpuType.toUpperCase() || autoGpuType + property string autoGpuType: "NONE" + property real gpuPerc + property real gpuTemp + property real gpuMemUsed + property real gpuMemTotal: 0 + property real memUsed + property real memTotal + readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0 + property real storageUsed + property real storageTotal + property real storagePerc: storageTotal > 0 ? storageUsed / storageTotal : 0 + + property real lastCpuIdle + property real lastCpuTotal + + property int refCount + + function formatKib(kib: real): var { + const mib = 1024; + const gib = 1024 ** 2; + const tib = 1024 ** 3; + + if (kib >= tib) + return { + value: kib / tib, + unit: "TiB" + }; + if (kib >= gib) + return { + value: kib / gib, + unit: "GiB" + }; + if (kib >= mib) + return { + value: kib / mib, + unit: "MiB" + }; + return { + value: kib, + unit: "KiB" + }; + } + + Timer { + running: root.refCount > 0 + interval: 3000 + repeat: true + triggeredOnStart: true + onTriggered: { + stat.reload(); + meminfo.reload(); + storage.running = true; + gpuUsage.running = true; + sensors.running = true; + } + } + + FileView { + id: stat + + path: "/proc/stat" + onLoaded: { + const data = text().match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/); + if (data) { + const stats = data.slice(1).map(n => parseInt(n, 10)); + const total = stats.reduce((a, b) => a + b, 0); + const idle = stats[3] + (stats[4] ?? 0); + + const totalDiff = total - root.lastCpuTotal; + const idleDiff = idle - root.lastCpuIdle; + root.cpuPerc = totalDiff > 0 ? (1 - idleDiff / totalDiff) : 0; + + root.lastCpuTotal = total; + root.lastCpuIdle = idle; + } + } + } + + FileView { + id: meminfo + + path: "/proc/meminfo" + onLoaded: { + const data = text(); + root.memTotal = parseInt(data.match(/MemTotal: *(\d+)/)[1], 10) || 1; + root.memUsed = (root.memTotal - parseInt(data.match(/MemAvailable: *(\d+)/)[1], 10)) || 0; + } + } + + Process { + id: storage + + command: ["sh", "-c", "df | grep '^/dev/' | awk '{print $1, $3, $4}'"] + stdout: StdioCollector { + onStreamFinished: { + const deviceMap = new Map(); + + for (const line of text.trim().split("\n")) { + if (line.trim() === "") + continue; + + const parts = line.trim().split(/\s+/); + if (parts.length >= 3) { + const device = parts[0]; + const used = parseInt(parts[1], 10) || 0; + const avail = parseInt(parts[2], 10) || 0; + + // Only keep the entry with the largest total space for each device + if (!deviceMap.has(device) || (used + avail) > (deviceMap.get(device).used + deviceMap.get(device).avail)) { + deviceMap.set(device, { + used: used, + avail: avail + }); + } + } + } + + let totalUsed = 0; + let totalAvail = 0; + + for (const [device, stats] of deviceMap) { + totalUsed += stats.used; + totalAvail += stats.avail; + } + + root.storageUsed = totalUsed; + root.storageTotal = totalUsed + totalAvail; + } + } + } + + Process { + id: gpuTypeCheck + + running: !Config.services.gpuType + command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"] + stdout: StdioCollector { + onStreamFinished: root.autoGpuType = text.trim() + } + } + + Process { + id: oneshotMem + command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"] + running: root.gpuType === "NVIDIA" && root.gpuMemTotal === 0 + stdout: StdioCollector { + onStreamFinished: { + root.gpuMemTotal = Number(this.text.trim()) + oneshotMem.running = false + } + } + } + + Process { + id: gpuUsage + + command: root.gpuType === "GENERIC" ? ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"] : root.gpuType === "NVIDIA" ? ["nvidia-smi", "--query-gpu=utilization.gpu,temperature.gpu,memory.used", "--format=csv,noheader,nounits"] : ["echo"] + stdout: StdioCollector { + onStreamFinished: { + if (root.gpuType === "GENERIC") { + const percs = text.trim().split("\n"); + const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0); + root.gpuPerc = sum / percs.length / 100; + } else if (root.gpuType === "NVIDIA") { + const [usage, temp, mem] = text.trim().split(","); + root.gpuPerc = parseInt(usage, 10) / 100; + root.gpuTemp = parseInt(temp, 10); + root.gpuMemUsed = parseInt(mem, 10) / root.gpuMemTotal; + } else { + root.gpuPerc = 0; + root.gpuTemp = 0; + } + } + } + } + + Process { + id: sensors + + command: ["sensors"] + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + stdout: StdioCollector { + onStreamFinished: { + let cpuTemp = text.match(/(?:Package id [0-9]+|Tdie):\s+((\+|-)[0-9.]+)(°| )C/); + if (!cpuTemp) + // If AMD Tdie pattern failed, try fallback on Tctl + cpuTemp = text.match(/Tctl:\s+((\+|-)[0-9.]+)(°| )C/); + + if (cpuTemp) + root.cpuTemp = parseFloat(cpuTemp[1]); + + if (root.gpuType !== "GENERIC") + return; + + let eligible = false; + let sum = 0; + let count = 0; + + for (const line of text.trim().split("\n")) { + if (line === "Adapter: PCI adapter") + eligible = true; + else if (line === "") + eligible = false; + else if (eligible) { + let match = line.match(/^(temp[0-9]+|GPU core|edge)+:\s+\+([0-9]+\.[0-9]+)(°| )C/); + if (!match) + // Fall back to junction/mem if GPU doesn't have edge temp (for AMD GPUs) + match = line.match(/^(junction|mem)+:\s+\+([0-9]+\.[0-9]+)(°| )C/); + + if (match) { + sum += parseFloat(match[2]); + count++; + } + } + } + + root.gpuTemp = count > 0 ? sum / count : 0; + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/TextRender.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/TextRender.qml new file mode 100644 index 0000000..715a3f1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/TextRender.qml @@ -0,0 +1,6 @@ +import QtQuick + +Text { + renderType: Text.NativeRendering + textFormat: Text.PlainText +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/ThemeIcons.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/ThemeIcons.qml new file mode 100644 index 0000000..714f114 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/ThemeIcons.qml @@ -0,0 +1,286 @@ +pragma Singleton + +import QtQuick +import Quickshell + +Singleton { + id: root + + property real scoreThreshold: 0.2 + + // Manual overrides for tricky apps + property var substitutions: ({ + "code-url-handler": "visual-studio-code", + "Code": "visual-studio-code", + "gnome-tweaks": "org.gnome.tweaks", + "pavucontrol-qt": "pavucontrol", + "wps": "wps-office2019-kprometheus", + "wpsoffice": "wps-office2019-kprometheus", + "footclient": "foot" + }) + + // Dynamic fixups + property var regexSubstitutions: [ + { + "regex": /^steam_app_(\d+)$/, + "replace": "steam_icon_$1" + }, + { + "regex": /Minecraft.*/, + "replace": "minecraft-launcher" + }, + { + "regex": /.*polkit.*/, + "replace": "system-lock-screen" + }, + { + "regex": /gcr.prompter/, + "replace": "system-lock-screen" + } + ] + + property list entryList: [] + property var preppedNames: [] + property var preppedIcons: [] + property var preppedIds: [] + + Component.onCompleted: refreshEntries() + + Connections { + target: DesktopEntries.applications + function onValuesChanged() { + refreshEntries(); + } + } + + function refreshEntries() { + if (typeof DesktopEntries === 'undefined') + return; + + const values = Array.from(DesktopEntries.applications.values); + if (values) { + entryList = values.sort((a, b) => a.name.localeCompare(b.name)); + updatePreppedData(); + } + } + + function updatePreppedData() { + if (typeof FuzzySort === 'undefined') + return; + + const list = Array.from(entryList); + preppedNames = list.map(a => ({ + name: FuzzySort.prepare(`${a.name} `), entry: a})); + preppedIcons = list.map(a => ({ + name: FuzzySort.prepare(`${a.icon} `), + entry: a + })); + preppedIds = list.map(a => ({ + name: FuzzySort.prepare(`${a.id} `), + entry: a + })); + } + + function iconForAppId(appId, fallbackName) { + const fallback = fallbackName || "application-x-executable"; + if (!appId) + return iconFromName(fallback, fallback); + + const entry = findAppEntry(appId); + if (entry) { + return iconFromName(entry.icon, fallback); + } + + return iconFromName(appId, fallback); + } + + // Robust lookup strategy + function findAppEntry(str) { + if (!str || str.length === 0) + return null; + + let result = null; + + if (result = checkHeuristic(str)) + return result; + if (result = checkSubstitutions(str)) + return result; + if (result = checkRegex(str)) + return result; + if (result = checkSimpleTransforms(str)) + return result; + if (result = checkFuzzySearch(str)) + return result; + if (result = checkCleanMatch(str)) + return result; + + return null; + } + + function iconFromName(iconName, fallbackName) { + const fallback = fallbackName || "application-x-executable"; + try { + if (iconName && typeof Quickshell !== 'undefined' && Quickshell.iconPath) { + const p = Quickshell.iconPath(iconName, fallback); + if (p && p !== "") + return p; + } + } catch (e) {} + + try { + return Quickshell.iconPath ? (Quickshell.iconPath(fallback, true) || "") : ""; + } catch (e2) { + return ""; + } + } + + function distroLogoPath() { + try { + return (typeof OSInfo !== 'undefined' && OSInfo.distroIconPath) ? OSInfo.distroIconPath : ""; + } catch (e) { + return ""; + } + } + + // --- Lookup Helpers --- + + function checkHeuristic(str) { + if (typeof DesktopEntries !== 'undefined' && DesktopEntries.heuristicLookup) { + const entry = DesktopEntries.heuristicLookup(str); + if (entry) + return entry; + } + return null; + } + + function checkSubstitutions(str) { + let effectiveStr = substitutions[str]; + if (!effectiveStr) + effectiveStr = substitutions[str.toLowerCase()]; + + if (effectiveStr && effectiveStr !== str) { + return findAppEntry(effectiveStr); + } + return null; + } + + function checkRegex(str) { + for (let i = 0; i < regexSubstitutions.length; i++) { + const sub = regexSubstitutions[i]; + const replaced = str.replace(sub.regex, sub.replace); + if (replaced !== str) { + return findAppEntry(replaced); + } + } + return null; + } + + function checkSimpleTransforms(str) { + if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId) + return null; + + const lower = str.toLowerCase(); + + const variants = [str, lower, getFromReverseDomain(str), getFromReverseDomain(str)?.toLowerCase(), normalizeWithHyphens(str), str.replace(/_/g, '-').toLowerCase(), str.replace(/-/g, '_').toLowerCase()]; + + for (let i = 0; i < variants.length; i++) { + const variant = variants[i]; + if (variant) { + const entry = DesktopEntries.byId(variant); + if (entry) + return entry; + } + } + return null; + } + + function checkFuzzySearch(str) { + if (typeof FuzzySort === 'undefined') + return null; + + // Check filenames (IDs) first + if (preppedIds.length > 0) { + let results = fuzzyQuery(str, preppedIds); + if (results.length === 0) { + const underscored = str.replace(/-/g, '_').toLowerCase(); + if (underscored !== str) + results = fuzzyQuery(underscored, preppedIds); + } + if (results.length > 0) + return results[0]; + } + + // Then icons + if (preppedIcons.length > 0) { + const results = fuzzyQuery(str, preppedIcons); + if (results.length > 0) + return results[0]; + } + + // Then names + if (preppedNames.length > 0) { + const results = fuzzyQuery(str, preppedNames); + if (results.length > 0) + return results[0]; + } + + return null; + } + + function checkCleanMatch(str) { + if (!str || str.length <= 3) + return null; + if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId) + return null; + + // Aggressive fallback: strip all separators + const cleanStr = str.toLowerCase().replace(/[\.\-_]/g, ''); + const list = Array.from(entryList); + + for (let i = 0; i < list.length; i++) { + const entry = list[i]; + const cleanId = (entry.id || "").toLowerCase().replace(/[\.\-_]/g, ''); + if (cleanId.includes(cleanStr) || cleanStr.includes(cleanId)) { + return entry; + } + } + return null; + } + + function fuzzyQuery(search, preppedData) { + if (!search || !preppedData || preppedData.length === 0) + return []; + return FuzzySort.go(search, preppedData, { + all: true, + key: "name" + }).map(r => r.obj.entry); + } + + function iconExists(iconName) { + if (!iconName || iconName.length === 0) + return false; + if (iconName.startsWith("/")) + return true; + + const path = Quickshell.iconPath(iconName, true); + return path && path.length > 0 && !path.includes("image-missing"); + } + + function getFromReverseDomain(str) { + if (!str) + return ""; + return str.split('.').slice(-1)[0]; + } + + function normalizeWithHyphens(str) { + if (!str) + return ""; + return str.toLowerCase().replace(/\s+/g, "-"); + } + + // Deprecated shim + function guessIcon(str) { + const entry = findAppEntry(str); + return entry ? entry.icon : "image-missing"; + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Time.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Time.qml new file mode 100644 index 0000000..11a67f7 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Time.qml @@ -0,0 +1,26 @@ +pragma Singleton + +import Quickshell + +Singleton { + property alias enabled: clock.enabled + readonly property date date: clock.date + readonly property int hours: clock.hours + readonly property int minutes: clock.minutes + readonly property int seconds: clock.seconds + + readonly property string timeStr: format("hh:mm") + readonly property list timeComponents: timeStr.split(":") + readonly property string hourStr: timeComponents[0] ?? "" + readonly property string minuteStr: timeComponents[1] ?? "" + readonly property string amPmStr: timeComponents[2] ?? "" + + function format(fmt: string): string { + return Qt.formatDateTime(clock.date, fmt); + } + + SystemClock { + id: clock + precision: SystemClock.Seconds + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/UPower.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/UPower.qml new file mode 100644 index 0000000..ed9f1ad --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/UPower.qml @@ -0,0 +1,13 @@ +pragma Singleton + +import Quickshell +import Quickshell.Services.UPower + + +Singleton { + id: root + + readonly property list devices: UPower.devices.values + readonly property bool onBattery: UPower.onBattery + readonly property UPowerDevice displayDevice: UPower.displayDevice +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Visibilities.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Visibilities.qml new file mode 100644 index 0000000..5ddde0c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Visibilities.qml @@ -0,0 +1,16 @@ +pragma Singleton + +import Quickshell + +Singleton { + property var screens: new Map() + property var bars: new Map() + + function load(screen: ShellScreen, visibilities: var): void { + screens.set(Hypr.monitorFor(screen), visibilities); + } + + function getForActive(): PersistentProperties { + return screens.get(Hypr.focusedMonitor); + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/WallpaperPath.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/WallpaperPath.qml new file mode 100644 index 0000000..33e4e0d --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/WallpaperPath.qml @@ -0,0 +1,26 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import qs.Paths + +Singleton { + id: root + + property alias currentWallpaperPath: adapter.currentWallpaperPath + property alias lockscreenBg: adapter.lockscreenBg + + FileView { + id: fileView + path: `${Paths.state}/wallpaper_path.json` + + watchChanges: true + onFileChanged: reload() + onAdapterUpdated: writeAdapter() + JsonAdapter { + id: adapter + property string currentWallpaperPath: "" + property string lockscreenBg: `${Paths.state}/lockscreen_bg.png` + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Wallpapers.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Wallpapers.qml new file mode 100644 index 0000000..068eff4 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Wallpapers.qml @@ -0,0 +1,62 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import ZShell.Models +import qs.Config +import qs.Modules +import qs.Helpers +import qs.Paths + +Searcher { + id: root + + property bool showPreview: false + readonly property string current: showPreview ? previewPath : actualCurrent + property string previewPath + property string actualCurrent: WallpaperPath.currentWallpaperPath + + function setWallpaper(path: string): void { + actualCurrent = path; + WallpaperPath.currentWallpaperPath = path; + if ( Config.general.color.wallust ) + Wallust.generateColors(WallpaperPath.currentWallpaperPath); + Quickshell.execDetached(["sh", "-c", `zshell-cli wallpaper lockscreen --input-image=${root.actualCurrent} --output-path=${Paths.state}/lockscreen_bg.png --blur-amount=${Config.lock.blurAmount}`]); + } + + function preview(path: string): void { + previewPath = path; + if ( Config.general.color.schemeGeneration ) + Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${previewPath} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]); + showPreview = true; + } + + function stopPreview(): void { + showPreview = false; + if ( Config.general.color.schemeGeneration ) + Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${root.actualCurrent} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]); + } + + list: wallpapers.entries + key: "relativePath" + useFuzzy: true + extraOpts: useFuzzy ? ({}) : ({ + forward: false + }) + + IpcHandler { + target: "wallpaper" + + function set(path: string): void { + root.setWallpaper(path); + } + } + + FileSystemModel { + id: wallpapers + + recursive: true + path: Config.general.wallpaperPath + filter: FileSystemModel.Images + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Wallust.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Wallust.qml new file mode 100644 index 0000000..dad85dd --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Wallust.qml @@ -0,0 +1,25 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick +import qs.Config + +Singleton { + id: root + + property var args + readonly property string mode: Config.general.color.mode + readonly property string threshold: mode === "dark" ? "--threshold=9" : "--dynamic-threshold" + + function generateColors(wallpaperPath) { + root.args = wallpaperPath; + wallustProc.running = true; + } + + Process { + id: wallustProc + command: ["wallust", "run", root.args, `--palette=${root.mode}`, "--ignore-sequence=cursor", `${root.threshold}` ] + running: false + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Weather.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Weather.qml new file mode 100644 index 0000000..df28df5 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Weather.qml @@ -0,0 +1,205 @@ +pragma Singleton + +import Quickshell +import QtQuick +import ZShell +import qs.Config + +Singleton { + id: root + + property string city + property string loc + property var cc + property list forecast + property list hourlyForecast + + readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert" + readonly property string description: cc?.weatherDesc ?? qsTr("No weather") + readonly property string temp: `${cc?.tempC ?? 0}°C` + readonly property string feelsLike: `${cc?.feelsLikeC ?? 0}°C` + readonly property int humidity: cc?.humidity ?? 0 + readonly property real windSpeed: cc?.windSpeed ?? 0 + readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), "h:mm") : "--:--" + readonly property string sunset: cc ? Qt.formatDateTime(new Date(cc.sunset), "h:mm") : "--:--" + + readonly property var cachedCities: new Map() + + function reload(): void { + const configLocation = Config.services.weatherLocation; + + if (configLocation) { + if (configLocation.indexOf(",") !== -1 && !isNaN(parseFloat(configLocation.split(",")[0]))) { + loc = configLocation; + fetchCityFromCoords(configLocation); + } else { + fetchCoordsFromCity(configLocation); + } + } else if (!loc || timer.elapsed() > 900) { + Requests.get("https://ipinfo.io/json", text => { + const response = JSON.parse(text); + if (response.loc) { + loc = response.loc; + city = response.city ?? ""; + timer.restart(); + } + }); + } + } + + function fetchCityFromCoords(coords: string): void { + if (cachedCities.has(coords)) { + city = cachedCities.get(coords); + return; + } + + const [lat, lon] = coords.split(","); + const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=geocodejson`; + Requests.get(url, text => { + const geo = JSON.parse(text).features?.[0]?.properties.geocoding; + if (geo) { + const geoCity = geo.type === "city" ? geo.name : geo.city; + city = geoCity; + cachedCities.set(coords, geoCity); + } else { + city = "Unknown City"; + } + }); + } + + function fetchCoordsFromCity(cityName: string): void { + const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(cityName)}&count=1&language=en&format=json`; + + Requests.get(url, text => { + const json = JSON.parse(text); + if (json.results && json.results.length > 0) { + const result = json.results[0]; + loc = result.latitude + "," + result.longitude; + city = result.name; + } else { + loc = ""; + reload(); + } + }); + } + + function fetchWeatherData(): void { + const url = getWeatherUrl(); + if (url === "") + return; + + Requests.get(url, text => { + const json = JSON.parse(text); + if (!json.current || !json.daily) + return; + + cc = { + weatherCode: json.current.weather_code, + weatherDesc: getWeatherCondition(json.current.weather_code), + tempC: Math.round(json.current.temperature_2m), + tempF: Math.round(toFahrenheit(json.current.temperature_2m)), + feelsLikeC: Math.round(json.current.apparent_temperature), + feelsLikeF: Math.round(toFahrenheit(json.current.apparent_temperature)), + humidity: json.current.relative_humidity_2m, + windSpeed: json.current.wind_speed_10m, + isDay: json.current.is_day, + sunrise: json.daily.sunrise[0], + sunset: json.daily.sunset[0] + }; + + const forecastList = []; + for (let i = 0; i < json.daily.time.length; i++) + forecastList.push({ + date: json.daily.time[i], + maxTempC: Math.round(json.daily.temperature_2m_max[i]), + maxTempF: Math.round(toFahrenheit(json.daily.temperature_2m_max[i])), + minTempC: Math.round(json.daily.temperature_2m_min[i]), + minTempF: Math.round(toFahrenheit(json.daily.temperature_2m_min[i])), + weatherCode: json.daily.weather_code[i], + icon: Icons.getWeatherIcon(json.daily.weather_code[i]) + }); + forecast = forecastList; + + const hourlyList = []; + const now = new Date(); + for (let i = 0; i < json.hourly.time.length; i++) { + const time = new Date(json.hourly.time[i]); + if (time < now) + continue; + + hourlyList.push({ + timestamp: json.hourly.time[i], + hour: time.getHours(), + tempC: Math.round(json.hourly.temperature_2m[i]), + tempF: Math.round(toFahrenheit(json.hourly.temperature_2m[i])), + weatherCode: json.hourly.weather_code[i], + icon: Icons.getWeatherIcon(json.hourly.weather_code[i]) + }); + } + hourlyForecast = hourlyList; + }); + } + + function toFahrenheit(celcius: real): real { + return celcius * 9 / 5 + 32; + } + + function getWeatherUrl(): string { + if (!loc || loc.indexOf(",") === -1) + return ""; + + const [lat, lon] = loc.split(","); + const baseUrl = "https://api.open-meteo.com/v1/forecast"; + const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"]; + + return baseUrl + "?" + params.join("&"); + } + + function getWeatherCondition(code: string): string { + const conditions = { + "0": "Clear", + "1": "Clear", + "2": "Partly cloudy", + "3": "Overcast", + "45": "Fog", + "48": "Fog", + "51": "Drizzle", + "53": "Drizzle", + "55": "Drizzle", + "56": "Freezing drizzle", + "57": "Freezing drizzle", + "61": "Light rain", + "63": "Rain", + "65": "Heavy rain", + "66": "Light rain", + "67": "Heavy rain", + "71": "Light snow", + "73": "Snow", + "75": "Heavy snow", + "77": "Snow", + "80": "Light rain", + "81": "Rain", + "82": "Heavy rain", + "85": "Light snow showers", + "86": "Heavy snow showers", + "95": "Thunderstorm", + "96": "Thunderstorm with hail", + "99": "Thunderstorm with hail" + }; + return conditions[code] || "Unknown"; + } + + onLocChanged: fetchWeatherData() + + // Refresh current location hourly + Timer { + interval: 3600000 // 1 hour + running: true + repeat: true + onTriggered: fetchWeatherData() + } + + ElapsedTimer { + id: timer + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Year.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Year.qml new file mode 100644 index 0000000..03ad712 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Helpers/Year.qml @@ -0,0 +1,420 @@ +import Quickshell.Io + +JsonObject { + property list week_0: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_1: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_2: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_3: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_4: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_5: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_6: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_7: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_8: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_9: [ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_10:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_11:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_12:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_13:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_14:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_15:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_16:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_17:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_18:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_19:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_20:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_21:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_22:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_23:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_24:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_25:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_26:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_27:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_28:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_29:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_30:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_31:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_32:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_33:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_34:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_35:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_36:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_37:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_38:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_39:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_40:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_41:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_42:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_43:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_44:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_45:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_46:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_47:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_48:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_49:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_50:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] + property list week_51:[ + 0, + 0, + 0, + 0, + 0, + 0, + ] +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/AudioPopup.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/AudioPopup.qml new file mode 100644 index 0000000..190ccb5 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/AudioPopup.qml @@ -0,0 +1,417 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Services.Pipewire +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import qs.Config +import qs.Components +import qs.Daemons +import qs.Helpers + +Item { + id: root + + implicitWidth: layout.implicitWidth + 5 * 2 + implicitHeight: layout.implicitHeight + 5 * 2 + + readonly property int topMargin: 0 + readonly property int rounding: 6 + + required property var wrapper + + ColumnLayout { + id: layout + + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + implicitWidth: stack.currentItem ? stack.currentItem.childrenRect.height : 0 + spacing: 12 + + RowLayout { + id: tabBar + spacing: 6 + Layout.fillWidth: true + property int tabHeight: 36 + + CustomClippingRect { + radius: 6 + Layout.fillWidth: true + Layout.preferredHeight: tabBar.tabHeight + + color: stack.currentIndex === 0 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer + + StateLayer { + + function onClicked(): void { + stack.currentIndex = 0; + } + + CustomText { + text: qsTr("Volumes") + anchors.centerIn: parent + color: stack.currentIndex === 0 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary + } + } + } + + CustomClippingRect { + radius: 6 + Layout.fillWidth: true + Layout.preferredHeight: tabBar.tabHeight + + color: stack.currentIndex === 1 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer + + StateLayer { + + function onClicked(): void { + stack.currentIndex = 1; + } + + CustomText { + text: qsTr("Devices") + anchors.centerIn: parent + color: stack.currentIndex === 1 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary + } + } + } + } + + StackLayout { + id: stack + Layout.fillWidth: true + Layout.preferredHeight: currentIndex === 0 ? vol.childrenRect.height : dev.childrenRect.height + currentIndex: 0 + + VolumesTab { id: vol } + DevicesTab { id: dev } + + Behavior on currentIndex { + SequentialAnimation { + ParallelAnimation { + Anim { + target: stack + property: "opacity" + to: 0 + duration: MaterialEasing.expressiveEffectsTime + } + + Anim { + target: stack + property: "scale" + to: 0.9 + duration: MaterialEasing.expressiveEffectsTime + } + } + + PropertyAction {} + + ParallelAnimation { + Anim { + target: stack + property: "opacity" + to: 1 + duration: MaterialEasing.expressiveEffectsTime + } + + Anim { + target: stack + property: "scale" + to: 1 + duration: MaterialEasing.expressiveEffectsTime + } + } + } + } + } + } + + component VolumesTab: ColumnLayout { + spacing: 12 + + CustomRect { + Layout.topMargin: root.topMargin + Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 + Layout.fillWidth: true + color: DynamicColors.tPalette.m3surfaceContainer + + radius: root.rounding + + RowLayout { + id: outputVolume + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.spacing.smaller + spacing: 15 + CustomRect { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignVCenter + color: DynamicColors.palette.m3primary + radius: 1000 + MaterialIcon { + anchors.centerIn: parent + color: DynamicColors.palette.m3onPrimary + text: "speaker" + font.pointSize: 22 + } + } + + ColumnLayout { + Layout.fillWidth: true + RowLayout { + Layout.fillWidth: true + + CustomText { + text: "Output Volume" + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + } + + CustomText { + text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`); + font.bold: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + } + + CustomMouseArea { + Layout.fillWidth: true + Layout.preferredHeight: 10 + Layout.bottomMargin: 5 + + CustomSlider { + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: 10 + value: Audio.volume + onMoved: Audio.setVolume(value) + + Behavior on value { Anim {} } + } + } + } + } + } + + + CustomRect { + Layout.topMargin: root.topMargin + Layout.fillWidth: true + Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 + color: DynamicColors.tPalette.m3surfaceContainer + + radius: root.rounding + + RowLayout { + id: inputVolume + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.spacing.smaller + spacing: 15 + Rectangle { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignVCenter + color: DynamicColors.palette.m3primary + radius: 1000 + MaterialIcon { + anchors.centerIn: parent + anchors.alignWhenCentered: false + color: DynamicColors.palette.m3onPrimary + text: "mic" + font.pointSize: 22 + } + } + + ColumnLayout { + Layout.fillWidth: true + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + CustomText { + text: "Input Volume" + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + } + + CustomText { + text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`); + font.bold: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + } + + CustomMouseArea { + Layout.fillWidth: true + Layout.bottomMargin: 5 + implicitHeight: 10 + + CustomSlider { + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: 10 + value: Audio.sourceVolume + onMoved: Audio.setSourceVolume(value) + + Behavior on value { Anim {} } + } + } + } + } + } + + Rectangle { + Layout.topMargin: root.topMargin + Layout.fillWidth: true + Layout.preferredHeight: 1 + + color: DynamicColors.tPalette.m3outline + } + + Repeater { + model: Audio.streams.filter(s => s.isSink) + + CustomRect { + id: appBox + + Layout.topMargin: root.topMargin + Layout.fillWidth: true + Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 + color: DynamicColors.tPalette.m3surfaceContainer + + radius: root.rounding + + + required property var modelData + required property int index + + RowLayout { + id: layoutVolume + anchors.fill: parent + anchors.margins: Appearance.spacing.smaller + spacing: 15 + + + CustomRect { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignVCenter + color: DynamicColors.palette.m3primary + radius: 1000 + MaterialIcon { + id: icon + anchors.centerIn: parent + text: "volume_up" + font.pointSize: 22 + color: DynamicColors.palette.m3onPrimary + + StateLayer { + radius: 1000 + onClicked: { + appBox.modelData.audio.muted = !appBox.modelData.audio.muted; + } + } + } + } + + ColumnLayout { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillHeight: true + + TextMetrics { + id: metrics + text: Audio.getStreamName(appBox.modelData) + elide: Text.ElideRight + elideWidth: root.width - 50 + } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + CustomText { + text: metrics.elidedText + elide: Text.ElideRight + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + } + + CustomText { + text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`); + font.bold: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + } + + CustomMouseArea { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + implicitHeight: 10 + CustomSlider { + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: 10 + value: appBox.modelData.audio.volume + onMoved: { + Audio.setStreamVolume(appBox.modelData, value) + } + } + } + } + } + } + } + } + + component DevicesTab: ColumnLayout { + spacing: 12 + + ButtonGroup { id: sinks } + ButtonGroup { id: sources } + + CustomText { + text: qsTr("Output device") + font.weight: 500 + } + + Repeater { + model: Audio.sinks + + CustomRadioButton { + required property PwNode modelData + + ButtonGroup.group: sinks + checked: Audio.sink?.id === modelData.id + onClicked: Audio.setAudioSink(modelData) + text: modelData.description + } + } + + CustomText { + Layout.topMargin: 10 + text: qsTr("Input device") + font.weight: 500 + } + + Repeater { + model: Audio.sources + + CustomRadioButton { + required property PwNode modelData + + ButtonGroup.group: sources + checked: Audio.source?.id === modelData.id + onClicked: Audio.setAudioSource(modelData) + text: modelData.description + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/AudioWidget.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/AudioWidget.qml new file mode 100644 index 0000000..114d56e --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/AudioWidget.qml @@ -0,0 +1,120 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Services.Pipewire +import qs.Daemons +import qs.Modules +import qs.Config +import qs.Components + +Item { + id: root + implicitWidth: expanded ? 300 : 150 + anchors.top: parent.top + anchors.bottom: parent.bottom + + property bool expanded: false + property color textColor: DynamicColors.palette.m3onSurface + property color barColor: DynamicColors.palette.m3primary + + Behavior on implicitWidth { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + height: 22 + radius: height / 2 + color: DynamicColors.tPalette.m3surfaceContainer + + Behavior on color { + CAnim {} + } + + Rectangle { + anchors.centerIn: parent + width: parent.width + height: parent.height + radius: width / 2 + color: "transparent" + border.color: "#30ffffff" + border.width: 0 + } + + RowLayout { + anchors { + fill: parent + leftMargin: 10 + rightMargin: 15 + } + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: 18 + text: Audio.muted ? "volume_off" : "volume_up" + color: Audio.muted ? DynamicColors.palette.m3error : root.textColor + } + + Rectangle { + Layout.fillWidth: true + + implicitHeight: 4 + radius: 20 + color: "#50ffffff" + + Rectangle { + id: sinkVolumeBar + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom + } + + implicitWidth: parent.width * ( Audio.volume ?? 0 ) + radius: parent.radius + color: Audio.muted ? DynamicColors.palette.m3error : root.barColor + Behavior on color { + CAnim {} + } + } + } + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: 18 + text: Audio.sourceMuted ? "mic_off" : "mic" + color: ( Audio.sourceMuted ?? false ) ? DynamicColors.palette.m3error : root.textColor + } + + Rectangle { + Layout.fillWidth: true + + implicitHeight: 4 + radius: 20 + color: "#50ffffff" + + Rectangle { + id: sourceVolumeBar + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom + } + + implicitWidth: parent.width * ( Audio.sourceVolume ?? 0 ) + radius: parent.radius + color: ( Audio.sourceMuted ?? false ) ? DynamicColors.palette.m3error : root.barColor + + Behavior on color { + CAnim {} + } + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Background.qml new file mode 100644 index 0000000..a920cc1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Background.qml @@ -0,0 +1,67 @@ +import QtQuick +import QtQuick.Shapes +import qs.Components +import qs.Config + +ShapePath { + id: root + + required property Wrapper wrapper + required property bool invertBottomRounding + readonly property real rounding: 8 + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + property real ibr: invertBottomRounding ? -1 : 1 + + strokeWidth: -1 + fillColor: DynamicColors.palette.m3surface + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY - root.roundingY * root.ibr + } + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY * root.ibr + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: root.invertBottomRounding ? PathArc.Clockwise : PathArc.Counterclockwise + } + + PathLine { + relativeX: root.wrapper.width - root.rounding * 2 + relativeY: 0 + } + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + + PathLine { + relativeX: 0 + relativeY: -( root.wrapper.height - root.roundingY * 2 ) + } + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Bar/BarLoader.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Bar/BarLoader.qml new file mode 100644 index 0000000..282a9d1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Bar/BarLoader.qml @@ -0,0 +1,226 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Hyprland +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules +import qs.Config +import qs.Helpers +import qs.Modules.UPower +import qs.Modules.Network + +RowLayout { + id: root + anchors.fill: parent + + readonly property int vPadding: 6 + required property Wrapper popouts + required property PersistentProperties visibilities + required property PanelWindow bar + required property ShellScreen screen + + function checkPopout(x: real): void { + const ch = childAt(x, 2) as WrappedLoader; + + if (!ch) { + if ( !popouts.currentName.includes("traymenu") ) + popouts.hasCurrent = false; + return; + } + + if ( visibilities.sidebar || visibilities.dashboard ) + return; + + const id = ch.id; + const top = ch.x; + const item = ch.item; + const itemWidth = item.implicitWidth; + + + if (id === "audio" && Config.barConfig.popouts.audio) { + popouts.currentName = "audio"; + popouts.currentCenter = Qt.binding( () => item.mapToItem(root, itemWidth / 2, 0 ).x ); + popouts.hasCurrent = true; + } else if ( id === "resources" && Config.barConfig.popouts.resources ) { + popouts.currentName = "resources"; + popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x ); + popouts.hasCurrent = true; + } else if ( id === "tray" && Config.barConfig.popouts.tray ) { + const index = Math.floor((( x - top ) / item.implicitWidth ) * item.items.count ); + const trayItem = item.items.itemAt( index ); + if ( trayItem ) { + // popouts.currentName = `traymenu${ index }`; + // popouts.currentCenter = Qt.binding( () => trayItem.mapToItem( root, trayItem.implicitWidth / 2, 0 ).x ); + // popouts.hasCurrent = true; + } else { + // popouts.hasCurrent = false; + } + } else if ( id === "clock" && Config.barConfig.popouts.clock ) { + // Calendar.displayYear = new Date().getFullYear(); + // Calendar.displayMonth = new Date().getMonth(); + // popouts.currentName = "calendar"; + // popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x ); + // popouts.hasCurrent = true; + } else if ( id === "network" && Config.barConfig.popouts.network ) { + popouts.currentName = "network"; + popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x ); + popouts.hasCurrent = true; + } else if ( id === "upower" && Config.barConfig.popouts.upower ) { + popouts.currentName = "upower"; + popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x ); + popouts.hasCurrent = true; + } + } + + CustomShortcut { + name: "toggle-overview" + + onPressed: { + Hyprland.refreshWorkspaces(); + Hyprland.refreshMonitors(); + if ( root.popouts.hasCurrent && root.popouts.currentName === "overview" ) { + root.popouts.hasCurrent = false; + } else { + root.popouts.currentName = "overview"; + root.popouts.currentCenter = root.width / 2; + root.popouts.hasCurrent = true; + } + } + } + + Repeater { + id: repeater + model: Config.barConfig.entries + + DelegateChooser { + role: "id" + + DelegateChoice { + roleValue: "spacer" + delegate: WrappedLoader { + Layout.fillWidth: true + } + } + DelegateChoice { + roleValue: "workspaces" + delegate: WrappedLoader { + sourceComponent: Workspaces { + bar: root.bar + } + } + } + DelegateChoice { + roleValue: "audio" + delegate: WrappedLoader { + sourceComponent: AudioWidget {} + } + } + DelegateChoice { + roleValue: "tray" + delegate: WrappedLoader { + sourceComponent: TrayWidget { + bar: root.bar + popouts: root.popouts + loader: root + } + } + } + DelegateChoice { + roleValue: "resources" + delegate: WrappedLoader { + sourceComponent: Resources {} + } + } + DelegateChoice { + roleValue: "updates" + delegate: WrappedLoader { + sourceComponent: UpdatesWidget {} + } + } + DelegateChoice { + roleValue: "notifBell" + delegate: WrappedLoader { + sourceComponent: NotifBell { + visibilities: root.visibilities + popouts: root.popouts + } + } + } + DelegateChoice { + roleValue: "clock" + delegate: WrappedLoader { + sourceComponent: Clock { + popouts: root.popouts + visibilities: root.visibilities + loader: root + } + } + } + DelegateChoice { + roleValue: "activeWindow" + delegate: WrappedLoader { + sourceComponent: WindowTitle { + bar: root + monitor: Brightness.getMonitorForScreen(root.screen) + } + } + } + DelegateChoice { + roleValue: "upower" + delegate: WrappedLoader { + sourceComponent: UPowerWidget {} + } + } + DelegateChoice { + roleValue: "network" + delegate: WrappedLoader { + sourceComponent: NetworkWidget {} + } + } + // DelegateChoice { + // roleValue: "dash" + // delegate: WrappedLoader { + // sourceComponent: DashWidget { + // visibilities: root.visibilities + // } + // } + // } + } + } + + component WrappedLoader: Loader { + required property bool enabled + required property string id + required property int index + + Layout.alignment: Qt.AlignVCenter + Layout.fillHeight: true + + function findFirstEnabled(): Item { + const count = repeater.count; + for (let i = 0; i < count; i++) { + const item = repeater.itemAt(i); + if (item?.enabled) + return item; + } + return null; + } + + function findLastEnabled(): Item { + for (let i = repeater.count - 1; i >= 0; i--) { + const item = repeater.itemAt(i); + if (item?.enabled) + return item; + } + return null; + } + + Layout.leftMargin: findFirstEnabled() === this ? root.vPadding : 0 + Layout.rightMargin: findLastEnabled() === this ? root.vPadding : 0 + + visible: enabled + active: enabled + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Bar/Border.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Bar/Border.qml new file mode 100644 index 0000000..8bb4e20 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Bar/Border.qml @@ -0,0 +1,49 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Effects +import qs.Modules +import qs.Config +import qs.Components + +Item { + id: root + + required property Item bar + required property PersistentProperties visibilities + + anchors.fill: parent + + CustomRect { + anchors.fill: parent + color: Config.barConfig.autoHide && !root.visibilities.bar ? "transparent" : DynamicColors.palette.m3surface + + layer.enabled: true + + layer.effect: MultiEffect { + maskSource: mask + maskEnabled: true + maskInverted: true + maskThresholdMin: 0.5 + maskSpreadAtMin: 1 + } + } + + Item { + id: mask + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + anchors.fill: parent + anchors.topMargin: Config.barConfig.autoHide && !root.visibilities.bar ? 4 : root.bar.implicitHeight + topLeftRadius: 8 + topRightRadius: 8 + Behavior on anchors.topMargin { + Anim {} + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/CalendarHeader.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/CalendarHeader.qml new file mode 100644 index 0000000..97d6b2b --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/CalendarHeader.qml @@ -0,0 +1,76 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers + +RowLayout { + spacing: 12 + + Rectangle { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + color: "transparent" + radius: 1000 + + MaterialIcon { + anchors.centerIn: parent + text: "arrow_back_2" + fill: 1 + font.pointSize: 24 + color: DynamicColors.palette.m3onSurface + } + + StateLayer { + onClicked: { + if (Calendar.displayMonth === 0) { + Calendar.displayMonth = 11; + Calendar.displayYear -= 1; + } else { + Calendar.displayMonth -= 1; + } + } + } + } + + CustomText { + text: new Date(Calendar.displayYear, Calendar.displayMonth, 1).toLocaleDateString( + Qt.locale(), + "MMMM yyyy" + ) + font.weight: 600 + font.pointSize: 14 + color: DynamicColors.palette.m3onSurface + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + } + + Rectangle { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + color: "transparent" + radius: 1000 + + MaterialIcon { + anchors.centerIn: parent + text: "arrow_back_2" + fill: 1 + font.pointSize: 24 + rotation: 180 + color: DynamicColors.palette.m3onSurface + } + + StateLayer { + onClicked: { + if (Calendar.displayMonth === 11) { + Calendar.displayMonth = 0; + Calendar.displayYear += 1; + } else { + Calendar.displayMonth += 1; + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/CalendarPopup.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/CalendarPopup.qml new file mode 100644 index 0000000..a25db29 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/CalendarPopup.qml @@ -0,0 +1,77 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers + +Item { + id: root + + required property Item wrapper + + implicitWidth: layout.childrenRect.width + layout.anchors.margins * 2 + implicitHeight: layout.childrenRect.height + layout.anchors.margins * 2 + + ColumnLayout { + id: layout + + anchors.centerIn: parent + anchors.margins: 16 + spacing: 16 + + // Header with month/year and navigation + CalendarHeader { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + } + + // Calendar grid + RowLayout { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + spacing: 12 + + ColumnLayout { + Layout.alignment: Qt.AlignTop + Layout.preferredHeight: childrenRect.height + Layout.preferredWidth: weekNumberColumn.width + spacing: 8 + + Item { + Layout.preferredHeight: dayOfWeekRow.height + } + + WeekNumberColumn { + id: weekNumberColumn + + Layout.alignment: Qt.AlignTop + Layout.preferredHeight: weekNumbers.values.length * 44 + } + } + + ColumnLayout { + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + spacing: 8 + + DayOfWeekRow { + id: dayOfWeekRow + locale: Qt.locale() + Layout.fillWidth: true + Layout.preferredHeight: 30 + } + + MonthGrid { + locale: Qt.locale() + + wrapper: root.wrapper + Layout.preferredWidth: childrenRect.width + Layout.preferredHeight: childrenRect.height + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/DayOfWeekRow.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/DayOfWeekRow.qml new file mode 100644 index 0000000..39505e5 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/DayOfWeekRow.qml @@ -0,0 +1,45 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers + +RowLayout { + id: root + + required property var locale + + spacing: 4 + + Repeater { + model: 7 + + Item { + required property int index + + Layout.fillWidth: true + Layout.preferredHeight: 30 + + readonly property string dayName: { + // Get the day name for this column + const dayIndex = (index + Calendar.weekStartDay) % 7; + return root.locale.dayName(dayIndex, Locale.ShortFormat); + } + + CustomText { + anchors.centerIn: parent + + text: parent.dayName + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: DynamicColors.palette.m3onSurfaceVariant + opacity: 0.8 + font.weight: 500 + font.pointSize: 11 + } + } + } +} + diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/MonthGrid.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/MonthGrid.qml new file mode 100644 index 0000000..d1e61c3 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/MonthGrid.qml @@ -0,0 +1,117 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers + +GridLayout { + id: root + + required property var locale + required property Item wrapper + + columns: 7 + rowSpacing: 4 + columnSpacing: 4 + uniformCellWidths: true + uniformCellHeights: true + + component Anim: NumberAnimation { + target: root + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + + Repeater { + id: repeater + model: ScriptModel { + values: Calendar.getWeeksForMonth(Calendar.displayMonth, Calendar.displayYear) + + Behavior on values { + SequentialAnimation { + id: switchAnim + ParallelAnimation { + Anim { + property: "opacity" + from: 1.0 + to: 0.0 + } + Anim { + property: "scale" + from: 1.0 + to: 0.8 + } + } + PropertyAction {} + ParallelAnimation { + Anim { + property: "opacity" + from: 0.0 + to: 1.0 + } + Anim { + property: "scale" + from: 0.8 + to: 1.0 + } + } + } + } + } + + Rectangle { + + required property var modelData + required property int index + + Layout.preferredWidth: 40 + Layout.preferredHeight: width + + + radius: 1000 + color: { + if (modelData.isToday) { + console.log(width); + return DynamicColors.palette.m3primaryContainer; + } + return "transparent"; + } + + Behavior on color { + ColorAnimation { duration: 200 } + } + + CustomText { + anchors.centerIn: parent + + text: parent.modelData.day.toString() + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + opacity: parent.modelData.isCurrentMonth ? 1.0 : 0.4 + color: { + if (parent.modelData.isToday) { + return DynamicColors.palette.m3onPrimaryContainer; + } + return DynamicColors.palette.m3onSurface; + } + + Behavior on color { + ColorAnimation { duration: 200 } + } + Behavior on opacity { + NumberAnimation { duration: 200 } + } + } + + StateLayer { + color: DynamicColors.palette.m3onSurface + onClicked: { + console.log(`Selected date: ${parent.modelData.day}/${parent.modelData.month + 1}/${parent.modelData.year}`); + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/WeekNumberColumn.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/WeekNumberColumn.qml new file mode 100644 index 0000000..8fdf5c1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Calendar/WeekNumberColumn.qml @@ -0,0 +1,45 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers + +ColumnLayout { + id: root + + spacing: 4 + + readonly property var weekNumbers: Calendar.getWeekNumbers(Calendar.displayMonth, Calendar.displayYear) + + Repeater { + model: ScriptModel { + values: root.weekNumbers + } + + Item { + id: weekItem + Layout.preferredHeight: 40 + Layout.preferredWidth: 20 + Layout.alignment: Qt.AlignHCenter + + required property int index + required property var modelData + + CustomText { + id: weekText + + anchors.centerIn: parent + + text: weekItem.modelData + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: DynamicColors.palette.m3onSurfaceVariant + opacity: 0.5 + font.pointSize: 10 + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Clock.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Clock.qml new file mode 100644 index 0000000..27d5505 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Clock.qml @@ -0,0 +1,45 @@ +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Config +import qs.Modules +import qs.Helpers as Helpers +import qs.Components + +Item { + id: root + required property PersistentProperties visibilities + required property Wrapper popouts + required property RowLayout loader + + implicitWidth: timeText.contentWidth + 5 * 2 + anchors.top: parent.top + anchors.bottom: parent.bottom + + CustomRect { + anchors.fill: parent + anchors.topMargin: 3 + anchors.bottomMargin: 3 + radius: 4 + color: "transparent" + CustomText { + id: timeText + + anchors.centerIn: parent + + text: Time.dateStr + color: DynamicColors.palette.m3onSurface + + Behavior on color { + CAnim {} + } + } + + StateLayer { + acceptedButtons: Qt.LeftButton + onClicked: { + root.visibilities.dashboard = !root.visibilities.dashboard; + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Content.qml new file mode 100644 index 0000000..2ab064c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Content.qml @@ -0,0 +1,168 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Services.SystemTray +import QtQuick +import qs.Config +import qs.Components +import qs.Modules.Calendar +import qs.Modules.WSOverview +import qs.Modules.Network +import qs.Modules.UPower + +Item { + id: root + + required property Item wrapper + readonly property Popout currentPopout: content.children.find(c => c.shouldBeActive) ?? null + readonly property Item current: currentPopout?.item ?? null + + implicitWidth: (currentPopout?.implicitWidth ?? 0) + 5 * 2 + implicitHeight: (currentPopout?.implicitHeight ?? 0) + 5 * 2 + + Item { + id: content + + anchors.fill: parent + + Popout { + name: "audio" + sourceComponent: AudioPopup { + wrapper: root.wrapper + } + } + + Popout { + name: "resources" + sourceComponent: ResourcePopout { + wrapper: root.wrapper + } + } + + Repeater { + model: ScriptModel { + values: [ ...SystemTray.items.values ] + } + + Popout { + id: trayMenu + + required property SystemTrayItem modelData + required property int index + + name: `traymenu${index}` + sourceComponent: trayMenuComponent + + Connections { + target: root.wrapper + + function onHasCurrentChanged(): void { + if ( root.wrapper.hasCurrent && trayMenu.shouldBeActive ) { + trayMenu.sourceComponent = null; + trayMenu.sourceComponent = trayMenuComponent; + } + } + } + + Component { + id: trayMenuComponent + + TrayMenuPopout { + popouts: root.wrapper + trayItem: trayMenu.modelData.menu + } + } + } + } + + Popout { + name: "calendar" + sourceComponent: CalendarPopup { + wrapper: root.wrapper + } + } + + Popout { + name: "overview" + + sourceComponent: OverviewPopout { + wrapper: root.wrapper + screen: root.wrapper.screen + } + } + + Popout { + name: "upower" + + sourceComponent: UPowerPopout { + wrapper: root.wrapper + } + } + + Popout { + name: "network" + + sourceComponent: NetworkPopout { + wrapper: root.wrapper + } + } + } + + component Popout: Loader { + id: popout + + required property string name + readonly property bool shouldBeActive: root.wrapper.currentName === name + + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + + opacity: 0 + scale: 0.8 + active: false + + states: State { + name: "active" + when: popout.shouldBeActive + + PropertyChanges { + popout.active: true + popout.opacity: 1 + popout.scale: 1 + } + } + + transitions: [ + Transition { + from: "active" + to: "" + + SequentialAnimation { + Anim { + properties: "opacity,scale" + duration: MaterialEasing.expressiveEffectsTime + } + PropertyAction { + target: popout + property: "active" + } + } + }, + Transition { + from: "" + to: "active" + + SequentialAnimation { + PropertyAction { + target: popout + property: "active" + } + Anim { + properties: "opacity,scale" + } + } + } + ] + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/DashWidget.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/DashWidget.qml new file mode 100644 index 0000000..72b1c93 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/DashWidget.qml @@ -0,0 +1,31 @@ +import Quickshell +import QtQuick +import qs.Config +import qs.Helpers +import qs.Components + +CustomRect { + id: root + + required property PersistentProperties visibilities + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: 6 + anchors.bottomMargin: 6 + implicitWidth: 40 + color: DynamicColors.tPalette.m3surfaceContainer + radius: 1000 + + StateLayer { + onClicked: { + root.visibilities.dashboard = !root.visibilities.dashboard; + } + } + + MaterialIcon { + anchors.centerIn: parent + text: "widgets" + color: DynamicColors.palette.m3onSurface + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Background.qml new file mode 100644 index 0000000..1c150e6 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Background.qml @@ -0,0 +1,65 @@ +import qs.Components +import qs.Config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: 8 + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: DynamicColors.palette.m3surface + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + + PathLine { + relativeX: root.wrapper.width - root.rounding * 2 + relativeY: 0 + } + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + + PathLine { + relativeX: 0 + relativeY: -(root.wrapper.height - root.roundingY * 2) + } + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Content.qml new file mode 100644 index 0000000..2e6866b --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Content.qml @@ -0,0 +1,88 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Config +import qs.Components + +Item { + id: root + + required property PersistentProperties visibilities + required property PersistentProperties state + readonly property real nonAnimWidth: view.implicitWidth + viewWrapper.anchors.margins * 2 + readonly property real nonAnimHeight: view.implicitHeight + viewWrapper.anchors.margins * 2 + + implicitWidth: nonAnimWidth + implicitHeight: nonAnimHeight + + ClippingRectangle { + id: viewWrapper + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Appearance.padding.smaller + + radius: 6 + color: "transparent" + + Item { + id: view + + readonly property int currentIndex: root.state.currentTab + readonly property Item currentItem: row.children[currentIndex] + + anchors.fill: parent + + implicitWidth: currentItem.implicitWidth + implicitHeight: currentItem.implicitHeight + + RowLayout { + id: row + + Pane { + index: 0 + sourceComponent: Dash { + state: root.state + visibilities: root.visibilities + } + } + } + } + } + + Behavior on implicitWidth { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on implicitHeight { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + component Pane: Loader { + id: pane + + required property int index + + Layout.alignment: Qt.AlignTop + + Component.onCompleted: active = Qt.binding(() => { + // Always keep current tab loaded + if (pane.index === view.currentIndex) + return true; + const vx = Math.floor(view.visibleArea.xPosition * view.contentWidth); + const vex = Math.floor(vx + view.visibleArea.widthRatio * view.contentWidth); + return (vx >= x && vx <= x + implicitWidth) || (vex >= x && vex <= x + implicitWidth); + }) + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash.qml new file mode 100644 index 0000000..27e1a80 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash.qml @@ -0,0 +1,147 @@ +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Helpers +import qs.Components +import qs.Paths +import qs.Modules +import qs.Config +import qs.Modules.Dashboard.Dash + +GridLayout { + id: root + + required property PersistentProperties visibilities + required property PersistentProperties state + readonly property bool dashboardVisible: visibilities.dashboard + + property int radius: 6 + + rowSpacing: Appearance.spacing.smaller + columnSpacing: Appearance.spacing.smaller + + opacity: 0 + scale: 0.9 + + onDashboardVisibleChanged: { + if (dashboardVisible) { + openAnim.start(); + } else { + closeAnim.start(); + } + } + + ParallelAnimation { + id: openAnim + Anim { + target: root + property: "opacity" + to: 1 + } + Anim { + target: root + property: "scale" + to: 1 + } + } + + ParallelAnimation { + id: closeAnim + Anim { + target: root + property: "opacity" + to: 0 + } + Anim { + target: root + property: "scale" + to: 0.9 + } + } + + Rect { + Layout.column: 2 + Layout.columnSpan: 3 + Layout.preferredWidth: user.implicitWidth + Layout.preferredHeight: user.implicitHeight + + radius: root.radius + + User { + id: user + + state: root.state + } + } + + Rect { + Layout.row: 0 + Layout.columnSpan: 2 + Layout.preferredWidth: Config.dashboard.sizes.weatherWidth + Layout.fillHeight: true + + radius: root.radius + + Weather {} + } + + // Rect { + // Layout.row: 1 + // Layout.preferredWidth: dateTime.implicitWidth + // Layout.fillHeight: true + // + // radius: root.radius + // + // DateTime { + // id: dateTime + // } + // } + + Rect { + Layout.row: 1 + Layout.column: 0 + Layout.columnSpan: 3 + Layout.fillWidth: true + Layout.preferredHeight: calendar.implicitHeight + + radius: root.radius + + Calendar { + id: calendar + + state: root.state + } + } + + Rect { + Layout.row: 1 + Layout.column: 3 + Layout.columnSpan: 2 + Layout.preferredWidth: resources.implicitWidth + Layout.fillHeight: true + + radius: root.radius + + Resources { + id: resources + } + } + + Rect { + Layout.row: 0 + Layout.column: 5 + Layout.rowSpan: 2 + Layout.preferredWidth: media.implicitWidth + Layout.fillHeight: true + + radius: root.radius + + Media { + id: media + } + } + + component Rect: CustomRect { + color: DynamicColors.tPalette.m3surfaceContainer + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Calendar.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Calendar.qml new file mode 100644 index 0000000..277278f --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Calendar.qml @@ -0,0 +1,252 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Components +import qs.Helpers +import qs.Config +import qs.Modules + +CustomMouseArea { + id: root + + required property var state + + readonly property int currMonth: state.currentDate.getMonth() + readonly property int currYear: state.currentDate.getFullYear() + + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: inner.implicitHeight + inner.anchors.margins * 2 + + acceptedButtons: Qt.MiddleButton + onClicked: root.state.currentDate = new Date() + + function onWheel(event: WheelEvent): void { + if (event.angleDelta.y > 0) + root.state.currentDate = new Date(root.currYear, root.currMonth - 1, 1); + else if (event.angleDelta.y < 0) + root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1); + } + + ColumnLayout { + id: inner + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.small + + RowLayout { + id: monthNavigationRow + + Layout.fillWidth: true + spacing: Appearance.spacing.small + + Item { + implicitWidth: implicitHeight + implicitHeight: prevMonthText.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + id: prevMonthStateLayer + + radius: Appearance.rounding.full + + function onClicked(): void { + root.state.currentDate = new Date(root.currYear, root.currMonth - 1, 1); + } + } + + MaterialIcon { + id: prevMonthText + + anchors.centerIn: parent + text: "chevron_left" + color: DynamicColors.palette.m3tertiary + font.pointSize: Appearance.font.size.normal + font.weight: 700 + } + } + + Item { + Layout.fillWidth: true + + implicitWidth: monthYearDisplay.implicitWidth + Appearance.padding.small * 2 + implicitHeight: monthYearDisplay.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + anchors.fill: monthYearDisplay + anchors.margins: -Appearance.padding.small + anchors.leftMargin: -Appearance.padding.normal + anchors.rightMargin: -Appearance.padding.normal + + radius: Appearance.rounding.full + disabled: { + const now = new Date(); + return root.currMonth === now.getMonth() && root.currYear === now.getFullYear(); + } + + function onClicked(): void { + root.state.currentDate = new Date(); + } + } + + CustomText { + id: monthYearDisplay + + anchors.centerIn: parent + text: grid.title + color: DynamicColors.palette.m3primary + font.pointSize: Appearance.font.size.normal + font.weight: 500 + font.capitalization: Font.Capitalize + } + } + + Item { + implicitWidth: implicitHeight + implicitHeight: nextMonthText.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + id: nextMonthStateLayer + + radius: Appearance.rounding.full + + function onClicked(): void { + root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1); + } + } + + MaterialIcon { + id: nextMonthText + + anchors.centerIn: parent + text: "chevron_right" + color: DynamicColors.palette.m3tertiary + font.pointSize: Appearance.font.size.normal + font.weight: 700 + } + } + } + + DayOfWeekRow { + id: daysRow + + Layout.fillWidth: true + locale: grid.locale + + delegate: CustomText { + required property var model + + horizontalAlignment: Text.AlignHCenter + text: model.shortName + font.weight: 500 + color: (model.day === 0) ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3onSurfaceVariant + } + } + + Item { + Layout.fillWidth: true + implicitHeight: grid.implicitHeight + + MonthGrid { + id: grid + + month: root.currMonth + year: root.currYear + + anchors.fill: parent + + spacing: 3 + locale: Qt.locale("en_SE") + + delegate: Item { + id: dayItem + + required property var model + + implicitWidth: implicitHeight + implicitHeight: text.implicitHeight + Appearance.padding.small * 2 + + CustomText { + id: text + + anchors.centerIn: parent + + horizontalAlignment: Text.AlignHCenter + text: grid.locale.toString(dayItem.model.day) + color: { + const dayOfWeek = dayItem.model.date.getUTCDay(); + if (dayOfWeek === 6) + return DynamicColors.palette.m3secondary; + + return DynamicColors.palette.m3onSurfaceVariant; + } + opacity: dayItem.model.today || dayItem.model.month === grid.month ? 1 : 0.4 + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + } + } + + CustomRect { + id: todayIndicator + + readonly property Item todayItem: grid.contentItem.children.find(c => c.model.today) ?? null + property Item today + + onTodayItemChanged: { + if (todayItem) + today = todayItem; + } + + x: today ? today.x + (today.width - implicitWidth) / 2 : 0 + y: today?.y ?? 0 + + implicitWidth: today?.implicitWidth ?? 0 + implicitHeight: today?.implicitHeight ?? 0 + + clip: true + radius: Appearance.rounding.full + color: DynamicColors.palette.m3primary + + opacity: todayItem ? 1 : 0 + scale: todayItem ? 1 : 0.7 + + Coloriser { + x: -todayIndicator.x + y: -todayIndicator.y + + implicitWidth: grid.width + implicitHeight: grid.height + + source: grid + sourceColor: DynamicColors.palette.m3onSurface + colorizationColor: DynamicColors.palette.m3onPrimary + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on x { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on y { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/DateTime.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/DateTime.qml new file mode 100644 index 0000000..5efa85b --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/DateTime.qml @@ -0,0 +1,50 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers + +Item { + id: root + + anchors.top: parent.top + anchors.bottom: parent.bottom + implicitWidth: 110 + + ColumnLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + spacing: 0 + + CustomText { + Layout.bottomMargin: -(font.pointSize * 0.4) + Layout.alignment: Qt.AlignHCenter + text: Time.hourStr + color: DynamicColors.palette.m3secondary + font.pointSize: 18 + font.family: "Rubik" + font.weight: 600 + } + + CustomText { + Layout.alignment: Qt.AlignHCenter + text: "•••" + color: DynamicColors.palette.m3primary + font.pointSize: 18 * 0.9 + font.family: "Rubik" + } + + CustomText { + Layout.topMargin: -(font.pointSize * 0.4) + Layout.alignment: Qt.AlignHCenter + text: Time.minuteStr + color: DynamicColors.palette.m3secondary + font.pointSize: 18 + font.family: "Rubik" + font.weight: 600 + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Media.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Media.qml new file mode 100644 index 0000000..3928d71 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Media.qml @@ -0,0 +1,238 @@ +import ZShell.Services +import QtQuick +import QtQuick.Shapes +import qs.Daemons +import qs.Components +import qs.Config +import qs.Helpers +import qs.Modules +import qs.Paths + +Item { + id: root + + property real playerProgress: { + const active = Players.active; + return active?.length ? active.position / active.length : 0; + } + + anchors.top: parent.top + anchors.bottom: parent.bottom + implicitWidth: Config.dashboard.sizes.mediaWidth + + Behavior on playerProgress { + Anim { + duration: Appearance.anim.durations.large + } + } + + Timer { + running: Players.active?.isPlaying ?? false + interval: Config.dashboard.mediaUpdateInterval + triggeredOnStart: true + repeat: true + onTriggered: Players.active?.positionChanged() + } + + ServiceRef { + service: Audio.beatTracker + } + + Shape { + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: "transparent" + strokeColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) + strokeWidth: Config.dashboard.sizes.mediaProgressThickness + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + centerX: cover.x + cover.width / 2 + centerY: cover.y + cover.height / 2 + radiusX: (cover.width + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + radiusY: (cover.height + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + startAngle: -90 - Config.dashboard.sizes.mediaProgressSweep / 2 + sweepAngle: Config.dashboard.sizes.mediaProgressSweep + } + + Behavior on strokeColor { + CAnim {} + } + } + + ShapePath { + fillColor: "transparent" + strokeColor: DynamicColors.palette.m3primary + strokeWidth: Config.dashboard.sizes.mediaProgressThickness + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + centerX: cover.x + cover.width / 2 + centerY: cover.y + cover.height / 2 + radiusX: (cover.width + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + radiusY: (cover.height + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + startAngle: -90 - Config.dashboard.sizes.mediaProgressSweep / 2 + sweepAngle: Config.dashboard.sizes.mediaProgressSweep * root.playerProgress + } + + Behavior on strokeColor { + CAnim {} + } + } + } + + CustomClippingRect { + id: cover + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large + Config.dashboard.sizes.mediaProgressThickness + Appearance.spacing.small + + implicitHeight: width + color: DynamicColors.tPalette.m3surfaceContainerHigh + radius: Infinity + + MaterialIcon { + anchors.centerIn: parent + + grade: 200 + text: "art_track" + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: (parent.width * 0.4) || 1 + } + + Image { + id: image + + anchors.fill: parent + + source: Players.active?.trackArtUrl ?? "" + asynchronous: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width + sourceSize.height: height + } + } + + CustomText { + id: title + + anchors.top: cover.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.normal + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title") + color: DynamicColors.palette.m3primary + font.pointSize: Appearance.font.size.normal + + width: parent.implicitWidth - Appearance.padding.large * 2 + elide: Text.ElideRight + } + + CustomText { + id: album + + anchors.top: title.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.small + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackAlbum ?? qsTr("No media")) || qsTr("Unknown album") + color: DynamicColors.palette.m3outline + font.pointSize: Appearance.font.size.small + + width: parent.implicitWidth - Appearance.padding.large * 2 + elide: Text.ElideRight + } + + CustomText { + id: artist + + anchors.top: album.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.small + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackArtist ?? qsTr("No media")) || qsTr("Unknown artist") + color: DynamicColors.palette.m3secondary + + width: parent.implicitWidth - Appearance.padding.large * 2 + elide: Text.ElideRight + } + + Row { + id: controls + + anchors.top: artist.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.smaller + + spacing: Appearance.spacing.small + + Control { + icon: "skip_previous" + canUse: Players.active?.canGoPrevious ?? false + + function onClicked(): void { + Players.active?.previous(); + } + } + + Control { + icon: Players.active?.isPlaying ? "pause" : "play_arrow" + canUse: Players.active?.canTogglePlaying ?? false + + function onClicked(): void { + Players.active?.togglePlaying(); + } + } + + Control { + icon: "skip_next" + canUse: Players.active?.canGoNext ?? false + + function onClicked(): void { + Players.active?.next(); + } + } + } + + component Control: CustomRect { + id: control + + required property string icon + required property bool canUse + function onClicked(): void { + } + + implicitWidth: Math.max(icon.implicitHeight, icon.implicitHeight) + Appearance.padding.small + implicitHeight: implicitWidth + + StateLayer { + disabled: !control.canUse + radius: Appearance.rounding.full + + function onClicked(): void { + control.onClicked(); + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.verticalCenterOffset: font.pointSize * 0.05 + + animate: true + text: control.icon + color: control.canUse ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline + font.pointSize: Appearance.font.size.large + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Resources.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Resources.qml new file mode 100644 index 0000000..969aca7 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Resources.qml @@ -0,0 +1,98 @@ +import QtQuick +import qs.Components +import qs.Helpers +import qs.Config + +Row { + id: root + + anchors.top: parent.top + anchors.bottom: parent.bottom + + padding: Appearance.padding.large + spacing: Appearance.spacing.large + + Ref { + service: SystemUsage + } + + Resource { + icon: "memory" + value: SystemUsage.cpuPerc + color: DynamicColors.palette.m3primary + } + + Resource { + icon: "memory_alt" + value: SystemUsage.memPerc + color: DynamicColors.palette.m3secondary + } + + Resource { + icon: "gamepad" + value: SystemUsage.gpuPerc + color: DynamicColors.palette.m3tertiary + } + + Resource { + icon: "host" + value: SystemUsage.gpuMemUsed + color: DynamicColors.palette.m3primary + } + + Resource { + icon: "hard_disk" + value: SystemUsage.storagePerc + color: DynamicColors.palette.m3secondary + } + + component Resource: Item { + id: res + + required property string icon + required property real value + required property color color + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: Appearance.padding.large + implicitWidth: icon.implicitWidth + + CustomRect { + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.bottom: icon.top + anchors.bottomMargin: Appearance.spacing.small + + implicitWidth: Config.dashboard.sizes.resourceProgessThickness + + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.full + + CustomRect { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + implicitHeight: res.value * parent.height + + color: res.color + radius: Appearance.rounding.full + } + } + + MaterialIcon { + id: icon + + anchors.bottom: parent.bottom + + text: res.icon + color: res.color + } + + Behavior on value { + Anim { + duration: Appearance.anim.durations.large + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/User.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/User.qml new file mode 100644 index 0000000..4295da0 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/User.qml @@ -0,0 +1,128 @@ +import qs.Components +import qs.Config +import qs.Paths +import qs.Helpers +import qs.Modules +import Quickshell +import QtQuick + +Row { + id: root + + required property PersistentProperties state + + padding: 20 + spacing: 12 + + CustomClippingRect { + implicitWidth: info.implicitHeight + implicitHeight: info.implicitHeight + + radius: 8 + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) + + MaterialIcon { + anchors.centerIn: parent + + text: "person" + fill: 1 + grade: 200 + font.pointSize: Math.floor(info.implicitHeight / 2) || 1 + } + + CachingImage { + id: pfp + + anchors.fill: parent + path: `${Paths.home}/.face` + } + } + + Column { + id: info + + anchors.verticalCenter: parent.verticalCenter + spacing: 12 + + Item { + id: line + + implicitWidth: icon.implicitWidth + text.width + text.anchors.leftMargin + implicitHeight: Math.max(icon.implicitHeight, text.implicitHeight) + + ColoredIcon { + id: icon + + anchors.left: parent.left + anchors.leftMargin: (Config.dashboard.sizes.infoIconSize - implicitWidth) / 2 + + source: SystemInfo.osLogo + implicitSize: Math.floor(13 * 1.34) + color: DynamicColors.palette.m3primary + } + + CustomText { + id: text + + anchors.verticalCenter: icon.verticalCenter + anchors.left: icon.right + anchors.leftMargin: icon.anchors.leftMargin + text: `: ${SystemInfo.osPrettyName || SystemInfo.osName}` + font.pointSize: 13 + + width: Config.dashboard.sizes.infoWidth + elide: Text.ElideRight + } + } + + InfoLine { + icon: "select_window_2" + text: SystemInfo.wm + colour: DynamicColors.palette.m3secondary + } + + InfoLine { + id: uptime + + icon: "timer" + text: qsTr("up %1").arg(SystemInfo.uptime) + colour: DynamicColors.palette.m3tertiary + } + } + + component InfoLine: Item { + id: line + + required property string icon + required property string text + required property color colour + + implicitWidth: icon.implicitWidth + text.width + text.anchors.leftMargin + implicitHeight: Math.max(icon.implicitHeight, text.implicitHeight) + + MaterialIcon { + id: icon + + anchors.left: parent.left + anchors.leftMargin: (Config.dashboard.sizes.infoIconSize - implicitWidth) / 2 + + fill: 1 + text: line.icon + color: line.colour + font.pointSize: 13 + } + + CustomText { + id: text + + anchors.verticalCenter: icon.verticalCenter + anchors.left: icon.right + anchors.leftMargin: icon.anchors.leftMargin + text: `: ${line.text}` + font.pointSize: 13 + + width: Config.dashboard.sizes.infoWidth + elide: Text.ElideRight + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Weather.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Weather.qml new file mode 100644 index 0000000..ef8cb76 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Dash/Weather.qml @@ -0,0 +1,56 @@ +import QtQuick +import qs.Helpers +import qs.Components +import qs.Config + +Item { + id: root + + anchors.centerIn: parent + + implicitWidth: icon.implicitWidth + info.implicitWidth + info.anchors.leftMargin + + Component.onCompleted: Weather.reload() + + MaterialIcon { + id: icon + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + animate: true + text: Weather.icon + color: DynamicColors.palette.m3secondary + font.pointSize: 54 + } + + Column { + id: info + + anchors.verticalCenter: parent.verticalCenter + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.large + + spacing: 8 + + CustomText { + anchors.horizontalCenter: parent.horizontalCenter + + animate: true + text: Weather.temp + color: DynamicColors.palette.m3primary + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + } + + CustomText { + anchors.horizontalCenter: parent.horizontalCenter + + animate: true + text: Weather.description + + elide: Text.ElideRight + width: Math.min(implicitWidth, root.parent.width - icon.implicitWidth - info.anchors.leftMargin - 24 * 2) + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Tabs.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Tabs.qml new file mode 100644 index 0000000..83246f4 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Tabs.qml @@ -0,0 +1,246 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Helpers +import qs.Modules +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Controls + +Item { + id: root + + required property real nonAnimWidth + required property PersistentProperties state + readonly property alias count: bar.count + + implicitHeight: bar.implicitHeight + indicator.implicitHeight + indicator.anchors.topMargin + separator.implicitHeight + + TabBar { + id: bar + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + + currentIndex: root.state.currentTab + background: null + + onCurrentIndexChanged: root.state.currentTab = currentIndex + + Tab { + iconName: "dashboard" + text: qsTr("Dashboard") + } + + Tab { + iconName: "queue_music" + text: qsTr("Media") + } + + Tab { + iconName: "speed" + text: qsTr("Performance") + } + + Tab { + iconName: "cloud" + text: qsTr("Weather") + } + + // Tab { + // iconName: "workspaces" + // text: qsTr("Workspaces") + // } + } + + Item { + id: indicator + + anchors.top: bar.bottom + + implicitWidth: bar.currentItem.implicitWidth + implicitHeight: 40 + + x: { + const tab = bar.currentItem; + const width = (root.nonAnimWidth - bar.spacing * (bar.count - 1)) / bar.count; + return width * tab.TabBar.index + (width - tab.implicitWidth) / 2; + } + + clip: true + + CustomRect { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: parent.implicitHeight * 2 + + color: DynamicColors.palette.m3primary + radius: 1000 + } + + Behavior on x { + Anim {} + } + + Behavior on implicitWidth { + Anim {} + } + } + + CustomRect { + id: separator + + anchors.top: indicator.bottom + anchors.left: parent.left + anchors.right: parent.right + + implicitHeight: 1 + color: DynamicColors.palette.m3outlineVariant + } + + component Tab: TabButton { + id: tab + + required property string iconName + readonly property bool current: TabBar.tabBar.currentItem === this + + background: null + + contentItem: CustomMouseArea { + id: mouse + + implicitWidth: Math.max(icon.width, label.width) + implicitHeight: icon.height + label.height + + cursorShape: Qt.PointingHandCursor + + onPressed: event => { + root.state.currentTab = tab.TabBar.index; + + const stateY = stateWrapper.y; + rippleAnim.x = event.x; + rippleAnim.y = event.y - stateY; + + const dist = (ox, oy) => ox * ox + oy * oy; + rippleAnim.radius = Math.sqrt(Math.max(dist(event.x, event.y + stateY), dist(event.x, stateWrapper.height - event.y), dist(width - event.x, event.y + stateY), dist(width - event.x, stateWrapper.height - event.y))); + + rippleAnim.restart(); + } + + function onWheel(event: WheelEvent): void { + if (event.angleDelta.y < 0) + root.state.currentTab = Math.min(root.state.currentTab + 1, bar.count - 1); + else if (event.angleDelta.y > 0) + root.state.currentTab = Math.max(root.state.currentTab - 1, 0); + } + + SequentialAnimation { + id: rippleAnim + + property real x + property real y + property real radius + + PropertyAction { + target: ripple + property: "x" + value: rippleAnim.x + } + PropertyAction { + target: ripple + property: "y" + value: rippleAnim.y + } + PropertyAction { + target: ripple + property: "opacity" + value: 0.08 + } + Anim { + target: ripple + properties: "implicitWidth,implicitHeight" + from: 0 + to: rippleAnim.radius * 2 + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + Anim { + target: ripple + property: "opacity" + to: 0 + easing.type: Easing.BezierSpline + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + ClippingRectangle { + id: stateWrapper + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + implicitHeight: parent.height + 8 * 2 + + color: "transparent" + radius: 8 + + CustomRect { + id: stateLayer + + anchors.fill: parent + + color: tab.current ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface + opacity: mouse.pressed ? 0.1 : tab.hovered ? 0.08 : 0 + + Behavior on opacity { + Anim {} + } + } + + CustomRect { + id: ripple + + radius: 1000 + color: tab.current ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface + opacity: 0 + + transform: Translate { + x: -ripple.width / 2 + y: -ripple.height / 2 + } + } + } + + MaterialIcon { + id: icon + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: label.top + + text: tab.iconName + color: tab.current ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant + fill: tab.current ? 1 : 0 + font.pointSize: 18 + + Behavior on fill { + Anim {} + } + } + + CustomText { + id: label + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + text: tab.text + color: tab.current ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Wrapper.qml new file mode 100644 index 0000000..4c1d272 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Dashboard/Wrapper.qml @@ -0,0 +1,90 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import qs.Components +import qs.Config + +Item { + id: root + + required property PersistentProperties visibilities + readonly property PersistentProperties dashState: PersistentProperties { + property int currentTab + property date currentDate: new Date() + + reloadableId: "dashboardState" + } + + readonly property real nonAnimHeight: state === "visible" ? (content.item?.nonAnimHeight ?? 0) : 0 + + visible: height > 0 + implicitHeight: 0 + implicitWidth: content.implicitWidth + + onStateChanged: { + if (state === "visible" && timer.running) { + timer.triggered(); + timer.stop(); + } + } + + states: State { + name: "visible" + when: root.visibilities.dashboard && Config.dashboard.enabled + + PropertyChanges { + root.implicitHeight: content.implicitHeight + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitHeight" + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitHeight" + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + ] + + Timer { + id: timer + + running: true + interval: Appearance.anim.durations.extraLarge + onTriggered: { + content.active = Qt.binding(() => (root.visibilities.dashboard && Config.dashboard.enabled) || root.visible); + content.visible = true; + } + } + + Loader { + id: content + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + visible: false + active: true + + sourceComponent: Content { + visibilities: root.visibilities + state: root.dashState + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/AppList.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/AppList.qml new file mode 100644 index 0000000..e80e635 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/AppList.qml @@ -0,0 +1,218 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import qs.Modules.Launcher.Services +import qs.Modules.Launcher.Items +import qs.Components +import qs.Config + +CustomListView { + id: root + + required property CustomTextField search + required property PersistentProperties visibilities + + model: ScriptModel { + id: model + + onValuesChanged: root.currentIndex = 0 + } + + verticalLayoutDirection: ListView.BottomToTop + spacing: Appearance.spacing.small + orientation: Qt.Vertical + implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing + + preferredHighlightBegin: 0 + preferredHighlightEnd: height + highlightRangeMode: ListView.ApplyRange + + highlightFollowsCurrentItem: false + highlight: CustomRect { + radius: 8 + color: DynamicColors.palette.m3onSurface + opacity: 0.08 + + y: root.currentItem?.y ?? 0 + implicitWidth: root.width + implicitHeight: root.currentItem?.implicitHeight ?? 0 + + Behavior on y { + Anim { + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } + } + + state: { + const text = search.text; + const prefix = Config.launcher.actionPrefix; + if (text.startsWith(prefix)) { + for (const action of ["calc", "scheme", "variant"]) + if (text.startsWith(`${prefix}${action} `)) + return action; + + return "actions"; + } + + return "apps"; + } + + states: [ + State { + name: "apps" + + PropertyChanges { + model.values: Apps.search(search.text) + root.delegate: appItem + } + }, + State { + name: "actions" + + PropertyChanges { + model.values: Actions.query(search.text) + root.delegate: actionItem + } + }, + State { + name: "calc" + + PropertyChanges { + model.values: [0] + root.delegate: calcItem + } + }, + ] + + transitions: Transition { + SequentialAnimation { + ParallelAnimation { + Anim { + target: root + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + Anim { + target: root + property: "scale" + from: 1 + to: 0.9 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } + PropertyAction { + targets: [model, root] + properties: "values,delegate" + } + ParallelAnimation { + Anim { + target: root + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + Anim { + target: root + property: "scale" + from: 0.9 + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } + PropertyAction { + targets: [root.add, root.remove] + property: "enabled" + value: true + } + } + } + + CustomScrollBar.vertical: CustomScrollBar { + flickable: root + } + + add: Transition { + enabled: !root.state + + Anim { + properties: "opacity,scale" + from: 0 + to: 1 + } + } + + remove: Transition { + enabled: !root.state + + Anim { + properties: "opacity,scale" + from: 1 + to: 0 + } + } + + move: Transition { + Anim { + property: "y" + } + Anim { + properties: "opacity,scale" + to: 1 + } + } + + addDisplaced: Transition { + Anim { + property: "y" + duration: Appearance.anim.durations.small + } + Anim { + properties: "opacity,scale" + to: 1 + } + } + + displaced: Transition { + Anim { + property: "y" + } + Anim { + properties: "opacity,scale" + to: 1 + } + } + + Component { + id: appItem + + AppItem { + visibilities: root.visibilities + } + } + + Component { + id: actionItem + + ActionItem { + list: root + } + } + + Component { + id: calcItem + + CalcItem { + list: root + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Background.qml new file mode 100644 index 0000000..5845020 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Background.qml @@ -0,0 +1,59 @@ +import QtQuick +import QtQuick.Shapes +import qs.Components +import qs.Config + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: Config.barConfig.rounding + 5 + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: DynamicColors.palette.m3surface + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: -(root.wrapper.height - root.roundingY * 2) + } + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: root.wrapper.width - root.rounding * 2 + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Content.qml new file mode 100644 index 0000000..660406f --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Content.qml @@ -0,0 +1,190 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import qs.Modules.Launcher.Services +import qs.Components +import qs.Helpers +import qs.Config + +Item { + id: root + + required property PersistentProperties visibilities + required property var panels + required property real maxHeight + + readonly property int padding: Appearance.padding.small + readonly property int rounding: Appearance.rounding.large + + implicitWidth: listWrapper.width + padding * 2 + implicitHeight: searchWrapper.height + listWrapper.height + padding * 2 + + Item { + id: listWrapper + + implicitWidth: list.width + implicitHeight: list.height + root.padding + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: searchWrapper.top + anchors.bottomMargin: root.padding + + ContentList { + id: list + + content: root + visibilities: root.visibilities + panels: root.panels + maxHeight: root.maxHeight - searchWrapper.implicitHeight - root.padding * 3 + search: search + padding: root.padding + rounding: root.rounding + } + } + + CustomRect { + id: searchWrapper + + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2) + radius: 8 + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: root.padding + + implicitHeight: Math.max(searchIcon.implicitHeight, search.implicitHeight, clearIcon.implicitHeight) + + MaterialIcon { + id: searchIcon + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: root.padding + 10 + + text: "search" + color: DynamicColors.palette.m3onSurfaceVariant + } + + CustomTextField { + id: search + + anchors.left: searchIcon.right + anchors.right: clearIcon.left + anchors.leftMargin: Appearance.spacing.small + anchors.rightMargin: Appearance.spacing.small + + topPadding: Appearance.padding.larger + bottomPadding: Appearance.padding.larger + + placeholderText: qsTr("Type \"%1\" for commands").arg(Config.launcher.actionPrefix) + + onAccepted: { + const currentItem = list.currentList?.currentItem; + if (currentItem) { + if (list.showWallpapers) { + if (DynamicColors.scheme === "dynamic" && currentItem.modelData.path !== Wallpapers.actualCurrent) + Wallpapers.previewColourLock = true; + Wallpapers.setWallpaper(currentItem.modelData.path); + root.visibilities.launcher = false; + } else if (text.startsWith(Config.launcher.actionPrefix)) { + if (text.startsWith(`${Config.launcher.actionPrefix}calc `)) + currentItem.onClicked(); + else + currentItem.modelData.onClicked(list.currentList); + } else { + Apps.launch(currentItem.modelData); + root.visibilities.launcher = false; + } + } + } + + Keys.onUpPressed: list.currentList?.incrementCurrentIndex() + Keys.onDownPressed: list.currentList?.decrementCurrentIndex() + + Keys.onEscapePressed: root.visibilities.launcher = false + + Keys.onPressed: event => { + if (!Config.launcher.vimKeybinds) + return; + + if (event.modifiers & Qt.ControlModifier) { + if (event.key === Qt.Key_J) { + list.currentList?.incrementCurrentIndex(); + event.accepted = true; + } else if (event.key === Qt.Key_K) { + list.currentList?.decrementCurrentIndex(); + event.accepted = true; + } + } else if (event.key === Qt.Key_Tab) { + list.currentList?.incrementCurrentIndex(); + event.accepted = true; + } else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) { + list.currentList?.decrementCurrentIndex(); + event.accepted = true; + } + } + + Component.onCompleted: forceActiveFocus() + + Connections { + target: root.visibilities + + function onLauncherChanged(): void { + if (!root.visibilities.launcher) + search.text = ""; + } + + function onSessionChanged(): void { + if (!root.visibilities.session) + search.forceActiveFocus(); + } + } + } + + MaterialIcon { + id: clearIcon + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: root.padding + 10 + + width: search.text ? implicitWidth : implicitWidth / 2 + opacity: { + if (!search.text) + return 0; + if (mouse.pressed) + return 0.7; + if (mouse.containsMouse) + return 0.8; + return 1; + } + + text: "close" + color: DynamicColors.palette.m3onSurfaceVariant + + MouseArea { + id: mouse + + anchors.fill: parent + hoverEnabled: true + cursorShape: search.text ? Qt.PointingHandCursor : undefined + + onClicked: search.text = "" + } + + Behavior on width { + Anim { + duration: Appearance.anim.durations.small + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/ContentList.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/ContentList.qml new file mode 100644 index 0000000..fadd172 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/ContentList.qml @@ -0,0 +1,170 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import qs.Paths +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config + +Item { + id: root + + required property var content + required property PersistentProperties visibilities + required property var panels + required property real maxHeight + required property CustomTextField search + required property int padding + required property int rounding + + readonly property bool showWallpapers: search.text.startsWith(`${Config.launcher.actionPrefix}wallpaper `) + readonly property Item currentList: showWallpapers ? wallpaperList.item : appList.item + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + clip: true + state: showWallpapers ? "wallpapers" : "apps" + + states: [ + State { + name: "apps" + + PropertyChanges { + root.implicitWidth: Config.launcher.sizes.itemWidth + root.implicitHeight: Math.min(root.maxHeight, appList.implicitHeight > 0 ? appList.implicitHeight : empty.implicitHeight) + appList.active: true + } + + AnchorChanges { + anchors.left: root.parent.left + anchors.right: root.parent.right + } + }, + State { + name: "wallpapers" + + PropertyChanges { + root.implicitWidth: Math.max(Config.launcher.sizes.itemWidth * 1.2, wallpaperList.implicitWidth) + root.implicitHeight: Config.launcher.sizes.wallpaperHeight + wallpaperList.active: true + } + } + ] + + Behavior on state { + SequentialAnimation { + Anim { + target: root + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.small + } + PropertyAction {} + Anim { + target: root + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.small + } + } + } + + Loader { + id: appList + + active: false + + anchors.fill: parent + + sourceComponent: AppList { + search: root.search + visibilities: root.visibilities + } + } + + Loader { + id: wallpaperList + + active: false + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + + sourceComponent: WallpaperList { + search: root.search + visibilities: root.visibilities + panels: root.panels + content: root.content + } + } + + Row { + id: empty + + opacity: root.currentList?.count === 0 ? 1 : 0 + scale: root.currentList?.count === 0 ? 1 : 0.5 + + spacing: Appearance.spacing.normal + padding: Appearance.padding.large + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + MaterialIcon { + text: root.state === "wallpapers" ? "wallpaper_slideshow" : "manage_search" + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.extraLarge + + anchors.verticalCenter: parent.verticalCenter + } + + Column { + anchors.verticalCenter: parent.verticalCenter + + CustomText { + text: root.state === "wallpapers" ? qsTr("No wallpapers found") : qsTr("No results") + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + CustomText { + text: root.state === "wallpapers" && Wallpapers.list.length === 0 ? qsTr("Try putting some wallpapers in %1").arg(Paths.shortenHome(Paths.wallsdir)) : qsTr("Try searching for something else") + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.normal + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + } + + Behavior on implicitWidth { + enabled: root.visibilities.launcher + + Anim { + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } + + Behavior on implicitHeight { + enabled: root.visibilities.launcher + + Anim { + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/ActionItem.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/ActionItem.qml new file mode 100644 index 0000000..ea869ce --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/ActionItem.qml @@ -0,0 +1,70 @@ +import QtQuick +import qs.Modules.Launcher.Services +import qs.Components +import qs.Helpers +import qs.Config + +Item { + id: root + + required property var modelData + required property var list + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.modelData?.onClicked(root.list); + } + } + + Item { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.larger + anchors.rightMargin: Appearance.padding.larger + anchors.margins: Appearance.padding.smaller + + MaterialIcon { + id: icon + + text: root.modelData?.icon ?? "" + font.pointSize: Appearance.font.size.extraLarge + + anchors.verticalCenter: parent.verticalCenter + } + + Item { + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.normal + anchors.verticalCenter: icon.verticalCenter + + implicitWidth: parent.width - icon.width + implicitHeight: name.implicitHeight + desc.implicitHeight + + CustomText { + id: name + + text: root.modelData?.name ?? "" + font.pointSize: Appearance.font.size.normal + } + + CustomText { + id: desc + + text: root.modelData?.desc ?? "" + font.pointSize: Appearance.font.size.small + color: DynamicColors.palette.m3outline + + elide: Text.ElideRight + width: root.width - icon.width - Appearance.rounding.normal * 2 + + anchors.top: name.bottom + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/AppItem.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/AppItem.qml new file mode 100644 index 0000000..ccee343 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/AppItem.qml @@ -0,0 +1,74 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import qs.Modules.Launcher.Services +import qs.Components +import qs.Helpers +import qs.Config +import qs.Modules + +Item { + id: root + + required property DesktopEntry modelData + required property PersistentProperties visibilities + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: 8 + + function onClicked(): void { + Apps.launch(root.modelData); + root.visibilities.launcher = false; + } + } + + Item { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.larger + anchors.rightMargin: Appearance.padding.larger + anchors.margins: Appearance.padding.smaller + + IconImage { + id: icon + + source: Quickshell.iconPath(root.modelData?.icon, "image-missing") + implicitSize: parent.height + + anchors.verticalCenter: parent.verticalCenter + } + + Item { + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.normal + anchors.verticalCenter: icon.verticalCenter + + implicitWidth: parent.width - icon.width + implicitHeight: name.implicitHeight + comment.implicitHeight + + CustomText { + id: name + + text: root.modelData?.name ?? "" + font.pointSize: Appearance.font.size.normal + } + + CustomText { + id: comment + + text: (root.modelData?.comment || root.modelData?.genericName || root.modelData?.name) ?? "" + font.pointSize: Appearance.font.size.small + color: DynamicColors.palette.m3outline + + elide: Text.ElideRight + width: root.width - icon.width - Appearance.rounding.normal * 2 + + anchors.top: name.bottom + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/CalcItem.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/CalcItem.qml new file mode 100644 index 0000000..56e937b --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/CalcItem.qml @@ -0,0 +1,124 @@ +import ZShell +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules +import qs.Helpers +import qs.Config + +Item { + id: root + + required property var list + readonly property string math: list.search.text.slice(`${Config.launcher.actionPrefix}calc `.length) + + function onClicked(): void { + Quickshell.execDetached(["wl-copy", Qalculator.eval(math, false)]); + root.list.visibilities.launcher = false; + } + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.onClicked(); + } + } + + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.larger + + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "function" + font.pointSize: Appearance.font.size.extraLarge + Layout.alignment: Qt.AlignVCenter + } + + CustomText { + id: result + + color: { + if (text.includes("error: ") || text.includes("warning: ")) + return DynamicColors.palette.m3error; + if (!root.math) + return DynamicColors.palette.m3onSurfaceVariant; + return DynamicColors.palette.m3onSurface; + } + + text: root.math.length > 0 ? Qalculator.eval(root.math) : qsTr("Type an expression to calculate") + elide: Text.ElideLeft + + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + } + + CustomRect { + color: DynamicColors.palette.m3tertiary + radius: Appearance.rounding.normal + clip: true + + implicitWidth: (stateLayer.containsMouse ? label.implicitWidth + label.anchors.rightMargin : 0) + icon.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: Math.max(label.implicitHeight, icon.implicitHeight) + Appearance.padding.small * 2 + + Layout.alignment: Qt.AlignVCenter + + StateLayer { + id: stateLayer + + color: DynamicColors.palette.m3onTertiary + + function onClicked(): void { + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.terminal, "fish", "-C", `exec qalc -i '${root.math}'`]); + root.list.visibilities.launcher = false; + } + } + + CustomText { + id: label + + anchors.verticalCenter: parent.verticalCenter + anchors.right: icon.left + anchors.rightMargin: Appearance.spacing.small + + text: qsTr("Open in calculator") + color: DynamicColors.palette.m3onTertiary + font.pointSize: Appearance.font.size.normal + + opacity: stateLayer.containsMouse ? 1 : 0 + + Behavior on opacity { + Anim {} + } + } + + MaterialIcon { + id: icon + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Appearance.padding.normal + + text: "open_in_new" + color: DynamicColors.palette.m3onTertiary + font.pointSize: Appearance.font.size.large + } + + Behavior on implicitWidth { + Anim { + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/WallpaperItem.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/WallpaperItem.qml new file mode 100644 index 0000000..d7533f9 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Items/WallpaperItem.qml @@ -0,0 +1,98 @@ +import ZShell.Models +import Quickshell +import QtQuick +import qs.Components +import qs.Helpers +import qs.Config +import qs.Modules + +Item { + id: root + + required property FileSystemEntry modelData + required property PersistentProperties visibilities + + scale: 0.5 + opacity: 0 + z: PathView.z ?? 0 + + Component.onCompleted: { + scale = Qt.binding(() => PathView.isCurrentItem ? 1 : PathView.onPath ? 0.8 : 0); + opacity = Qt.binding(() => PathView.onPath ? 1 : 0); + } + + implicitWidth: image.width + Appearance.padding.larger * 2 + implicitHeight: image.height + label.height + Appearance.spacing.small / 2 + Appearance.padding.large + Appearance.padding.normal + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + console.log(root.modelData.path); + Wallpapers.setWallpaper(root.modelData.path); + root.visibilities.launcher = false; + } + } + + Elevation { + anchors.fill: image + radius: image.radius + opacity: root.PathView.isCurrentItem ? 1 : 0 + level: 4 + + Behavior on opacity { + Anim {} + } + } + + CustomClippingRect { + id: image + + anchors.horizontalCenter: parent.horizontalCenter + y: Appearance.padding.large + color: DynamicColors.tPalette.m3surfaceContainer + radius: Appearance.rounding.normal + + implicitWidth: Config.launcher.sizes.wallpaperWidth + implicitHeight: implicitWidth / 16 * 9 + + MaterialIcon { + anchors.centerIn: parent + text: "image" + color: DynamicColors.tPalette.m3outline + font.pointSize: Appearance.font.size.extraLarge * 2 + font.weight: 600 + } + + CachingImage { + path: root.modelData.path + smooth: !root.PathView.view.moving + cache: true + + anchors.fill: parent + } + } + + CustomText { + id: label + + anchors.top: image.bottom + anchors.topMargin: Appearance.spacing.small / 2 + anchors.horizontalCenter: parent.horizontalCenter + + width: image.width - Appearance.padding.normal * 2 + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + renderType: Text.QtRendering + text: root.modelData.relativePath + font.pointSize: Appearance.font.size.normal + } + + Behavior on scale { + Anim {} + } + + Behavior on opacity { + Anim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Services/Actions.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Services/Actions.qml new file mode 100644 index 0000000..f428656 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Services/Actions.qml @@ -0,0 +1,51 @@ +pragma Singleton + +import qs.Modules.Launcher +import qs.Helpers +import qs.Config +import Quickshell +import QtQuick + +Searcher { + id: root + + function transformSearch(search: string): string { + return search.slice(Config.launcher.actionPrefix.length); + } + + list: variants.instances + useFuzzy: Config.launcher.useFuzzy.actions + + Variants { + id: variants + + model: Config.launcher.actions.filter(a => (a.enabled ?? true)) + + Action {} + } + + component Action: QtObject { + required property var modelData + readonly property string name: modelData.name ?? qsTr("Unnamed") + readonly property string desc: modelData.description ?? qsTr("No description") + readonly property string icon: modelData.icon ?? "help_outline" + readonly property list command: modelData.command ?? [] + readonly property bool enabled: modelData.enabled ?? true + readonly property bool dangerous: modelData.dangerous ?? false + + function onClicked(list: AppList): void { + if (command.length === 0) + return; + + if (command[0] === "autocomplete" && command.length > 1) { + list.search.text = `${Config.launcher.actionPrefix}${command[1]} `; + } else if (command[0] === "setMode" && command.length > 1) { + list.visibilities.launcher = false; + Colours.setMode(command[1]); + } else { + list.visibilities.launcher = false; + Quickshell.execDetached(command); + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Services/Apps.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Services/Apps.qml new file mode 100644 index 0000000..27d54a1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Services/Apps.qml @@ -0,0 +1,78 @@ +pragma Singleton + +import ZShell +import Quickshell +import qs.Config +import qs.Helpers +import qs.Paths + +Searcher { + id: root + + function launch(entry: DesktopEntry): void { + appDb.incrementFrequency(entry.id); + + if (entry.runInTerminal) + Quickshell.execDetached({ + command: ["app2unit", "--", ...Config.general.apps.terminal, `${Quickshell.shellDir}/assets/wrap_term_launch.sh`, ...entry.command], + workingDirectory: entry.workingDirectory + }); + else + Quickshell.execDetached({ + command: ["app2unit", "--", ...entry.command], + workingDirectory: entry.workingDirectory + }); + } + + function search(search: string): list { + const prefix = Config.launcher.specialPrefix; + + if (search.startsWith(`${prefix}i `)) { + keys = ["id", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}c `)) { + keys = ["categories", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}d `)) { + keys = ["comment", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}e `)) { + keys = ["execString", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}w `)) { + keys = ["startupClass", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}g `)) { + keys = ["genericName", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}k `)) { + keys = ["keywords", "name"]; + weights = [0.9, 0.1]; + } else { + keys = ["name"]; + weights = [1]; + + if (!search.startsWith(`${prefix}t `)) + return query(search).map(e => e.entry); + } + + const results = query(search.slice(prefix.length + 2)).map(e => e.entry); + if (search.startsWith(`${prefix}t `)) + return results.filter(a => a.runInTerminal); + return results; + } + + function selector(item: var): string { + return keys.map(k => item[k]).join(" "); + } + + list: appDb.apps + useFuzzy: Config.launcher.useFuzzy.apps + + AppDb { + id: appDb + + path: `${Paths.state}/apps.sqlite` + entries: DesktopEntries.applications.values + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/WallpaperList.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/WallpaperList.qml new file mode 100644 index 0000000..a898190 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/WallpaperList.qml @@ -0,0 +1,97 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import qs.Components +import qs.Helpers +import qs.Config +import qs.Modules.Launcher.Items + +PathView { + id: root + + required property CustomTextField search + required property var visibilities + required property var panels + required property var content + + readonly property int itemWidth: Config.launcher.sizes.wallpaperWidth * 0.8 + Appearance.padding.larger * 2 + + readonly property int numItems: { + const screen = QsWindow.window?.screen; + if (!screen) + return 0; + + // Screen width - 4x outer rounding - 2x max side thickness (cause centered) + const barMargins = panels.bar.implicitWidth; + let outerMargins = 0; + if (panels.popouts.hasCurrent && panels.popouts.currentCenter + panels.popouts.nonAnimHeight / 2 > screen.height - content.implicitHeight) + outerMargins = panels.popouts.nonAnimWidth; + if ((visibilities.utilities || visibilities.sidebar) && panels.utilities.implicitWidth > outerMargins) + outerMargins = panels.utilities.implicitWidth; + const maxWidth = screen.width - Config.barConfig.rounding * 4 - (barMargins + outerMargins) * 2; + + if (maxWidth <= 0) + return 0; + + const maxItemsOnScreen = Math.floor(maxWidth / itemWidth); + const visible = Math.min(maxItemsOnScreen, Config.launcher.maxWallpapers, scriptModel.values.length); + + if (visible === 2) + return 1; + if (visible > 1 && visible % 2 === 0) + return visible - 1; + return visible; + } + + model: ScriptModel { + id: scriptModel + + readonly property string search: root.search.text.split(" ").slice(1).join(" ") + + values: Wallpapers.query(search) + onValuesChanged: root.currentIndex = search ? 0 : values.findIndex(w => w.path === Wallpapers.actualCurrent) + } + + Component.onCompleted: currentIndex = Wallpapers.list.findIndex(w => w.path === Wallpapers.actualCurrent) + Component.onDestruction: Wallpapers.stopPreview() + + onCurrentItemChanged: { + if (currentItem) + Wallpapers.preview(currentItem.modelData.path); + } + + implicitWidth: Math.min(numItems, count) * itemWidth + pathItemCount: numItems + cacheItemCount: 4 + + snapMode: PathView.SnapToItem + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + highlightRangeMode: PathView.StrictlyEnforceRange + + delegate: WallpaperItem { + visibilities: root.visibilities + } + + path: Path { + startY: root.height / 2 + + PathAttribute { + name: "z" + value: 0 + } + PathLine { + x: root.width / 2 + relativeY: 0 + } + PathAttribute { + name: "z" + value: 1 + } + PathLine { + x: root.width + relativeY: 0 + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Wrapper.qml new file mode 100644 index 0000000..35b7932 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Launcher/Wrapper.qml @@ -0,0 +1,130 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import qs.Components +import qs.Config + +Item { + id: root + + required property ShellScreen screen + required property PersistentProperties visibilities + required property var panels + + readonly property bool shouldBeActive: visibilities.launcher + property int contentHeight + + readonly property real maxHeight: { + let max = screen.height - Appearance.spacing.large; + if (visibilities.dashboard) + max -= panels.dashboard.nonAnimHeight; + return max; + } + + onMaxHeightChanged: timer.start() + + visible: height > 0 + implicitHeight: 0 + implicitWidth: content.implicitWidth + + onShouldBeActiveChanged: { + if (shouldBeActive) { + timer.stop(); + hideAnim.stop(); + showAnim.start(); + } else { + showAnim.stop(); + hideAnim.start(); + } + } + + SequentialAnimation { + id: showAnim + + Anim { + target: root + property: "implicitHeight" + to: root.contentHeight + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + ScriptAction { + script: root.implicitHeight = Qt.binding(() => content.implicitHeight) + } + } + + SequentialAnimation { + id: hideAnim + + ScriptAction { + script: root.implicitHeight = root.implicitHeight + } + Anim { + target: root + property: "implicitHeight" + to: 0 + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } + + Connections { + target: Config.launcher + + function onEnabledChanged(): void { + timer.start(); + } + + function onMaxShownChanged(): void { + timer.start(); + } + } + + Connections { + target: DesktopEntries.applications + + function onValuesChanged(): void { + if (DesktopEntries.applications.values.length < Config.launcher.maxAppsShown) + timer.start(); + } + } + + Timer { + id: timer + + interval: Appearance.anim.durations.small + onRunningChanged: { + if (running && !root.shouldBeActive) { + content.visible = false; + content.active = true; + } else { + root.contentHeight = Math.min(root.maxHeight, content.implicitHeight); + content.active = Qt.binding(() => root.shouldBeActive || root.visible); + content.visible = true; + if (showAnim.running) { + showAnim.stop(); + showAnim.start(); + } + } + } + } + + Loader { + id: content + + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + + visible: false + active: false + Component.onCompleted: timer.start() + + sourceComponent: Content { + visibilities: root.visibilities + panels: root.panels + maxHeight: root.maxHeight + + Component.onCompleted: root.contentHeight = implicitHeight + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Center.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Center.qml new file mode 100644 index 0000000..7293d84 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Center.qml @@ -0,0 +1,399 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Paths +import qs.Components +import qs.Helpers +import qs.Config +import qs.Modules + +ColumnLayout { + id: root + + required property var lock + readonly property real centerScale: Math.min(1, (lock.screen?.height ?? 1440) / 1440) + readonly property int centerWidth: Config.lock.sizes.centerWidth * centerScale + + Layout.preferredWidth: centerWidth + Layout.fillWidth: false + Layout.fillHeight: true + + spacing: Appearance.spacing.large * 2 + + RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: Appearance.spacing.small + + CustomText { + Layout.alignment: Qt.AlignVCenter + text: Time.hourStr + color: DynamicColors.palette.m3secondary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) + font.family: Appearance.font.family.clock + font.bold: true + } + + CustomText { + Layout.alignment: Qt.AlignVCenter + text: ":" + color: DynamicColors.palette.m3primary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) + font.family: Appearance.font.family.clock + font.bold: true + } + + CustomText { + Layout.alignment: Qt.AlignVCenter + text: Time.minuteStr + color: DynamicColors.palette.m3secondary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) + font.family: Appearance.font.family.clock + font.bold: true + } + } + + CustomText { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: -Appearance.padding.large * 2 + + text: Time.format("dddd, d MMMM yyyy") + color: DynamicColors.palette.m3tertiary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * root.centerScale) + font.family: Appearance.font.family.mono + font.bold: true + } + + CustomClippingRect { + Layout.topMargin: Appearance.spacing.large * 2 + Layout.alignment: Qt.AlignHCenter + + implicitWidth: root.centerWidth / 2 + implicitHeight: root.centerWidth / 2 + + color: DynamicColors.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + MaterialIcon { + anchors.centerIn: parent + + text: "person" + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: Math.floor(root.centerWidth / 4) + } + + CachingImage { + id: pfp + + anchors.fill: parent + path: `${Paths.home}/.face` + } + } + + CustomRect { + Layout.alignment: Qt.AlignHCenter + + implicitWidth: root.centerWidth * 0.8 + implicitHeight: input.implicitHeight + Appearance.padding.small * 2 + + color: DynamicColors.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + focus: true + onActiveFocusChanged: { + if (!activeFocus) + forceActiveFocus(); + } + + Keys.onPressed: event => { + if (root.lock.unlocking) + return; + + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) + inputField.placeholder.animate = false; + + root.lock.pam.handleKey(event); + } + + StateLayer { + hoverEnabled: false + cursorShape: Qt.IBeamCursor + + function onClicked(): void { + parent.forceActiveFocus(); + } + } + + RowLayout { + id: input + + anchors.fill: parent + anchors.margins: Appearance.padding.small + spacing: Appearance.spacing.normal + + Item { + implicitWidth: implicitHeight + implicitHeight: fprintIcon.implicitHeight + Appearance.padding.small * 2 + + MaterialIcon { + id: fprintIcon + + anchors.centerIn: parent + animate: true + text: { + if (root.lock.pam.fprint.tries >= Config.lock.maxFprintTries) + return "fingerprint_off"; + if (root.lock.pam.fprint.active) + return "fingerprint"; + return "lock"; + } + color: root.lock.pam.fprint.tries >= Config.lock.maxFprintTries ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurface + opacity: root.lock.pam.passwd.active ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + CircularIndicator { + anchors.fill: parent + running: root.lock.pam.passwd.active + } + } + + InputField { + id: inputField + + pam: root.lock.pam + } + + CustomRect { + implicitWidth: implicitHeight + implicitHeight: enterIcon.implicitHeight + Appearance.padding.small * 2 + + color: root.lock.pam.buffer ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.full + + StateLayer { + color: root.lock.pam.buffer ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface + + function onClicked(): void { + root.lock.pam.passwd.start(); + } + } + + MaterialIcon { + id: enterIcon + + anchors.centerIn: parent + text: "arrow_forward" + color: root.lock.pam.buffer ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface + font.weight: 500 + } + } + } + } + + Item { + Layout.fillWidth: true + Layout.topMargin: -Appearance.spacing.large + + implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight) + + Behavior on implicitHeight { + Anim {} + } + + CustomText { + id: stateMessage + + readonly property string msg: { + if (Hypr.kbLayout !== Hypr.defaultKbLayout) { + if (Hypr.capsLock && Hypr.numLock) + return qsTr("Caps lock and Num lock are ON.\nKeyboard layout: %1").arg(Hypr.kbLayoutFull); + if (Hypr.capsLock) + return qsTr("Caps lock is ON. Kb layout: %1").arg(Hypr.kbLayoutFull); + if (Hypr.numLock) + return qsTr("Num lock is ON. Kb layout: %1").arg(Hypr.kbLayoutFull); + return qsTr("Keyboard layout: %1").arg(Hypr.kbLayoutFull); + } + + if (Hypr.capsLock && Hypr.numLock) + return qsTr("Caps lock and Num lock are ON."); + if (Hypr.capsLock) + return qsTr("Caps lock is ON."); + if (Hypr.numLock) + return qsTr("Num lock is ON."); + + return ""; + } + + property bool shouldBeVisible + + onMsgChanged: { + if (msg) { + if (opacity > 0) { + animate = true; + text = msg; + animate = false; + } else { + text = msg; + } + shouldBeVisible = true; + } else { + shouldBeVisible = false; + } + } + + anchors.left: parent.left + anchors.right: parent.right + + scale: shouldBeVisible && !message.msg ? 1 : 0.7 + opacity: shouldBeVisible && !message.msg ? 1 : 0 + color: DynamicColors.palette.m3onSurfaceVariant + animateProp: "opacity" + + font.family: Appearance.font.family.mono + horizontalAlignment: Qt.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + lineHeight: 1.2 + + Behavior on scale { + Anim {} + } + + Behavior on opacity { + Anim {} + } + } + + CustomText { + id: message + + readonly property Pam pam: root.lock.pam + readonly property string msg: { + if (pam.fprintState === "error") + return qsTr("FP ERROR: %1").arg(pam.fprint.message); + if (pam.state === "error") + return qsTr("PW ERROR: %1").arg(pam.passwd.message); + + if (pam.lockMessage) + return pam.lockMessage; + + if (pam.state === "max" && pam.fprintState === "max") + return qsTr("Maximum password and fingerprint attempts reached."); + if (pam.state === "max") { + if (pam.fprint.available) + return qsTr("Maximum password attempts reached. Please use fingerprint."); + return qsTr("Maximum password attempts reached."); + } + if (pam.fprintState === "max") + return qsTr("Maximum fingerprint attempts reached. Please use password."); + + if (pam.state === "fail") { + if (pam.fprint.available) + return qsTr("Incorrect password. Please try again or use fingerprint."); + return qsTr("Incorrect password. Please try again."); + } + if (pam.fprintState === "fail") + return qsTr("Fingerprint not recognized (%1/%2). Please try again or use password.").arg(pam.fprint.tries).arg(Config.lock.maxFprintTries); + + return ""; + } + + anchors.left: parent.left + anchors.right: parent.right + + scale: 0.7 + opacity: 0 + color: DynamicColors.palette.m3error + + font.pointSize: Appearance.font.size.small + font.family: Appearance.font.family.mono + horizontalAlignment: Qt.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + + onMsgChanged: { + if (msg) { + if (opacity > 0) { + animate = true; + text = msg; + animate = false; + + exitAnim.stop(); + if (scale < 1) + appearAnim.restart(); + else + flashAnim.restart(); + } else { + text = msg; + exitAnim.stop(); + appearAnim.restart(); + } + } else { + appearAnim.stop(); + flashAnim.stop(); + exitAnim.start(); + } + } + + Connections { + target: root.lock.pam + + function onFlashMsg(): void { + exitAnim.stop(); + if (message.scale < 1) + appearAnim.restart(); + else + flashAnim.restart(); + } + } + + Anim { + id: appearAnim + + target: message + properties: "scale,opacity" + to: 1 + onFinished: flashAnim.restart() + } + + SequentialAnimation { + id: flashAnim + + loops: 2 + + FlashAnim { + to: 0.3 + } + FlashAnim { + to: 1 + } + } + + ParallelAnimation { + id: exitAnim + + Anim { + target: message + property: "scale" + to: 0.7 + duration: Appearance.anim.durations.large + } + Anim { + target: message + property: "opacity" + to: 0 + duration: Appearance.anim.durations.large + } + } + } + } + + component FlashAnim: NumberAnimation { + target: message + property: "opacity" + duration: Appearance.anim.durations.small + easing.type: Easing.Linear + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Content.qml new file mode 100644 index 0000000..3174d8c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Content.qml @@ -0,0 +1,82 @@ +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Helpers +import qs.Config + +RowLayout { + id: root + + required property var lock + + spacing: Appearance.spacing.large * 2 + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + CustomRect { + Layout.fillWidth: true + implicitHeight: weather.implicitHeight + + topLeftRadius: Appearance.rounding.large + radius: Appearance.rounding.small + color: DynamicColors.tPalette.m3surfaceContainer + + WeatherInfo { + id: weather + + rootHeight: root.height + } + } + + CustomRect { + Layout.fillWidth: true + implicitHeight: resources.implicitHeight + + radius: Appearance.rounding.small + color: DynamicColors.tPalette.m3surfaceContainer + + Resources { + id: resources + } + } + + CustomClippingRect { + Layout.fillWidth: true + Layout.fillHeight: true + + bottomLeftRadius: Appearance.rounding.large + radius: Appearance.rounding.small + color: DynamicColors.tPalette.m3surfaceContainer + + Media { + id: media + + lock: root.lock + } + } + } + + Center { + lock: root.lock + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + CustomRect { + Layout.fillWidth: true + Layout.fillHeight: true + + topRightRadius: Appearance.rounding.large + bottomRightRadius: Appearance.rounding.large + radius: Appearance.rounding.small + color: DynamicColors.tPalette.m3surfaceContainer + + NotifDock { + lock: root.lock + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Fetch.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Fetch.qml new file mode 100644 index 0000000..bdc93ef --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Fetch.qml @@ -0,0 +1,164 @@ +pragma ComponentBehavior: Bound + +import Quickshell.Services.UPower +import QtQuick +import QtQuick.Layouts +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config + +ColumnLayout { + id: root + + anchors.fill: parent + anchors.margins: Appearance.padding.large * 2 + anchors.topMargin: Appearance.padding.large + + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + spacing: Appearance.spacing.normal + + CustomRect { + implicitWidth: prompt.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: prompt.implicitHeight + Appearance.padding.normal * 2 + + color: DynamicColors.palette.m3primary + radius: Appearance.rounding.small + + MonoText { + id: prompt + + anchors.centerIn: parent + text: ">" + font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal + color: DynamicColors.palette.m3onPrimary + } + } + + MonoText { + Layout.fillWidth: true + text: "caelestiafetch.sh" + font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal + elide: Text.ElideRight + } + + WrappedLoader { + Layout.fillHeight: true + active: !iconLoader.active + + sourceComponent: OsLogo {} + } + } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + spacing: height * 0.15 + + WrappedLoader { + id: iconLoader + + Layout.fillHeight: true + active: root.width > 320 + + sourceComponent: OsLogo {} + } + + ColumnLayout { + Layout.fillWidth: true + Layout.topMargin: Appearance.padding.normal + Layout.bottomMargin: Appearance.padding.normal + Layout.leftMargin: iconLoader.active ? 0 : width * 0.1 + spacing: Appearance.spacing.normal + + WrappedLoader { + Layout.fillWidth: true + active: !batLoader.active && root.height > 200 + + sourceComponent: FetchText { + text: `OS : ${SystemInfo.osPrettyName || SysInfo.osName}` + } + } + + WrappedLoader { + Layout.fillWidth: true + active: root.height > (batLoader.active ? 200 : 110) + + sourceComponent: FetchText { + text: `WM : ${SystemInfo.wm}` + } + } + + WrappedLoader { + Layout.fillWidth: true + active: !batLoader.active || root.height > 110 + + sourceComponent: FetchText { + text: `USER: ${SystemInfo.user}` + } + } + + FetchText { + text: `UP : ${SystemInfo.uptime}` + } + + WrappedLoader { + id: batLoader + + Layout.fillWidth: true + active: UPower.displayDevice.isLaptopBattery + + sourceComponent: FetchText { + text: `BATT: ${[UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state) ? "(+) " : ""}${Math.round(UPower.displayDevice.percentage * 100)}%` + } + } + } + } + + WrappedLoader { + Layout.alignment: Qt.AlignHCenter + active: root.height > 180 + + sourceComponent: RowLayout { + spacing: Appearance.spacing.large + + Repeater { + model: Math.max(0, Math.min(8, root.width / (Appearance.font.size.larger * 2 + Appearance.spacing.large))) + + CustomRect { + required property int index + + implicitWidth: implicitHeight + implicitHeight: Appearance.font.size.larger * 2 + color: DynamicColors.palette[`term${index}`] + radius: Appearance.rounding.small + } + } + } + } + + component WrappedLoader: Loader { + visible: active + } + + component OsLogo: ColoredIcon { + source: SystemInfo.osLogo + implicitSize: height + color: DynamicColors.palette.m3primary + layer.enabled: Config.lock.recolorLogo || SystemInfo.isDefaultLogo + } + + component FetchText: MonoText { + Layout.fillWidth: true + font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal + elide: Text.ElideRight + } + + component MonoText: CustomText { + font.family: Appearance.font.family.mono + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/IdleInhibitor.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/IdleInhibitor.qml new file mode 100644 index 0000000..e5312de --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/IdleInhibitor.qml @@ -0,0 +1,39 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Wayland +import qs.Config +import qs.Helpers + +Scope { + id: root + + required property Lock lock + readonly property bool enabled: !Players.list.some( p => p.isPlaying ) + + function handleIdleAction( action: var ): void { + if ( !action ) + return; + + if ( action === "lock" ) + lock.lock.locked = true; + else if ( action === "unlock" ) + lock.lock.locked = false; + else if ( typeof action === "string" ) + Hypr.dispatch( action ); + else + Quickshell.execDetached( action ); + } + + Variants { + model: Config.general.idle.timeouts + + IdleMonitor { + required property var modelData + + enabled: root.enabled && modelData.timeout > 0 ? true : false + timeout: modelData.timeout + onIsIdleChanged: root.handleIdleAction( isIdle ? modelData.idleAction : modelData.activeAction ) + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/InputField.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/InputField.qml new file mode 100644 index 0000000..1bfc40d --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/InputField.qml @@ -0,0 +1,150 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config + +Item { + id: root + + required property Pam pam + readonly property alias placeholder: placeholder + property string buffer + + Layout.fillWidth: true + Layout.fillHeight: true + + clip: true + + Connections { + target: root.pam + + function onBufferChanged(): void { + if (root.pam.buffer.length > root.buffer.length) { + charList.bindImWidth(); + } else if (root.pam.buffer.length === 0) { + charList.implicitWidth = charList.implicitWidth; + placeholder.animate = true; + } + + root.buffer = root.pam.buffer; + } + } + + CustomText { + id: placeholder + + anchors.centerIn: parent + + text: { + if (root.pam.passwd.active) + return qsTr("Loading..."); + if (root.pam.state === "max") + return qsTr("You have reached the maximum number of tries"); + return qsTr("Enter your password"); + } + + animate: true + color: root.pam.passwd.active ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline + font.pointSize: Appearance.font.size.normal + font.family: Appearance.font.family.mono + + opacity: root.buffer ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + ListView { + id: charList + + readonly property int fullWidth: count * (implicitHeight + spacing) - spacing + + function bindImWidth(): void { + imWidthBehavior.enabled = false; + implicitWidth = Qt.binding(() => fullWidth); + imWidthBehavior.enabled = true; + } + + anchors.centerIn: parent + anchors.horizontalCenterOffset: implicitWidth > root.width ? -(implicitWidth - root.width) / 2 : 0 + + implicitWidth: fullWidth + implicitHeight: Appearance.font.size.normal + + orientation: Qt.Horizontal + spacing: Appearance.spacing.small / 2 + interactive: false + + model: ScriptModel { + values: root.buffer.split("") + } + + delegate: CustomRect { + id: ch + + implicitWidth: implicitHeight + implicitHeight: charList.implicitHeight + + color: DynamicColors.palette.m3onSurface + radius: Appearance.rounding.small / 2 + + opacity: 0 + scale: 0 + Component.onCompleted: { + opacity = 1; + scale = 1; + } + ListView.onRemove: removeAnim.start() + + SequentialAnimation { + id: removeAnim + + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: true + } + ParallelAnimation { + Anim { + target: ch + property: "opacity" + to: 0 + } + Anim { + target: ch + property: "scale" + to: 0.5 + } + } + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: false + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + + Behavior on implicitWidth { + id: imWidthBehavior + + Anim {} + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Lock.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Lock.qml new file mode 100644 index 0000000..54b41a4 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Lock.qml @@ -0,0 +1,52 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Wayland +import Quickshell.Hyprland +import Quickshell.Io +import QtQuick +import QtQuick.Effects +import qs.Components +import qs.Config + +Scope { + id: root + + property alias lock: lock + property int seenOnce: 0 + + WlSessionLock { + id: lock + + signal unlock + signal requestLock + + LockSurface { + id: lockSurface + lock: lock + pam: pam + } + } + + Pam { + id: pam + + lock: lock + } + + IpcHandler { + target: "lock" + + function lock() { + return lock.locked = true; + } + } + + CustomShortcut { + name: "lock" + description: "Lock the current session" + onPressed: { + lock.locked = true; + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/LockSurface.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/LockSurface.qml new file mode 100644 index 0000000..fe3d77c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/LockSurface.qml @@ -0,0 +1,192 @@ +pragma ComponentBehavior: Bound + +import Quickshell.Wayland +import QtQuick +import QtQuick.Effects +import qs.Config +import qs.Helpers +import qs.Components + +WlSessionLockSurface { + id: root + + required property WlSessionLock lock + required property Pam pam + + readonly property alias unlocking: unlockAnim.running + + color: "transparent" + + Connections { + target: root.lock + + function onUnlock(): void { + unlockAnim.start(); + } + } + + SequentialAnimation { + id: unlockAnim + + ParallelAnimation { + Anim { + target: lockContent + properties: "implicitWidth,implicitHeight" + to: lockContent.size + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: lockBg + property: "radius" + to: lockContent.radius + } + Anim { + target: content + property: "scale" + to: 0 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: content + property: "opacity" + to: 0 + duration: Appearance.anim.durations.small + } + Anim { + target: lockIcon + property: "opacity" + to: 1 + duration: Appearance.anim.durations.large + } + SequentialAnimation { + PauseAnimation { + duration: Appearance.anim.durations.small + } + Anim { + target: lockContent + property: "opacity" + to: 0 + } + } + } + PropertyAction { + target: root.lock + property: "locked" + value: false + } + } + + ParallelAnimation { + id: initAnim + + running: true + + SequentialAnimation { + ParallelAnimation { + Anim { + target: lockContent + property: "scale" + to: 1 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + ParallelAnimation { + Anim { + target: lockIcon + property: "opacity" + to: 0 + } + Anim { + target: content + property: "opacity" + to: 1 + } + Anim { + target: content + property: "scale" + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: lockBg + property: "radius" + to: Appearance.rounding.large * 1.5 + } + Anim { + target: lockContent + property: "implicitWidth" + to: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult * Config.lock.sizes.ratio + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: lockContent + property: "implicitHeight" + to: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + + Image { + id: background + anchors.fill: parent + source: WallpaperPath.lockscreenBg + } + + Item { + id: lockContent + + readonly property int size: lockIcon.implicitHeight + Appearance.padding.large * 4 + readonly property int radius: size / 4 * Appearance.rounding.scale + + anchors.centerIn: parent + implicitWidth: size + implicitHeight: size + + scale: 0 + + CustomRect { + id: lockBg + + anchors.fill: parent + color: DynamicColors.palette.m3surface + radius: lockContent.radius + opacity: DynamicColors.transparency.enabled ? DynamicColors.transparency.base : 1 + + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + blurMax: 15 + shadowColor: Qt.alpha(DynamicColors.palette.m3shadow, 0.7) + } + } + + MaterialIcon { + id: lockIcon + + anchors.centerIn: parent + text: "lock" + font.pointSize: Appearance.font.size.extraLarge * 4 + font.bold: true + } + + Content { + id: content + + anchors.centerIn: parent + width: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult * Config.lock.sizes.ratio - Appearance.padding.large * 2 + height: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult - Appearance.padding.large * 2 + + lock: root + opacity: 0 + scale: 0 + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Media.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Media.qml new file mode 100644 index 0000000..4509a6d --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Media.qml @@ -0,0 +1,205 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config + +Item { + id: root + + required property var lock + + anchors.fill: parent + + Image { + anchors.fill: parent + source: Players.active?.trackArtUrl ?? "" + + asynchronous: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width + sourceSize.height: height + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: mask + } + + opacity: status === Image.Ready ? 1 : 0 + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.extraLarge + } + } + } + + Rectangle { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + gradient: Gradient { + orientation: Gradient.Horizontal + + GradientStop { + position: 0 + color: Qt.rgba(0, 0, 0, 0.5) + } + GradientStop { + position: 0.4 + color: Qt.rgba(0, 0, 0, 0.2) + } + GradientStop { + position: 0.8 + color: Qt.rgba(0, 0, 0, 0) + } + } + } + + ColumnLayout { + id: layout + + anchors.fill: parent + anchors.margins: Appearance.padding.large + + CustomText { + Layout.topMargin: Appearance.padding.large + Layout.bottomMargin: Appearance.spacing.larger + text: qsTr("Now playing") + color: DynamicColors.palette.m3onSurfaceVariant + font.family: Appearance.font.family.mono + font.weight: 500 + } + + CustomText { + Layout.fillWidth: true + animate: true + text: Players.active?.trackArtist ?? qsTr("No media") + color: DynamicColors.palette.m3primary + horizontalAlignment: Text.AlignHCenter + font.pointSize: Appearance.font.size.large + font.family: Appearance.font.family.mono + font.weight: 600 + elide: Text.ElideRight + } + + CustomText { + Layout.fillWidth: true + animate: true + text: Players.active?.trackTitle ?? qsTr("No media") + horizontalAlignment: Text.AlignHCenter + font.pointSize: Appearance.font.size.larger + font.family: Appearance.font.family.mono + elide: Text.ElideRight + } + + RowLayout { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Appearance.spacing.large * 1.2 + Layout.bottomMargin: Appearance.padding.large + + spacing: Appearance.spacing.large + + PlayerControl { + icon: "skip_previous" + + function onClicked(): void { + if (Players.active?.canGoPrevious) + Players.active.previous(); + } + } + + PlayerControl { + animate: true + icon: active ? "pause" : "play_arrow" + colour: "Primary" + level: active ? 2 : 1 + active: Players.active?.isPlaying ?? false + + function onClicked(): void { + if (Players.active?.canTogglePlaying) + Players.active.togglePlaying(); + } + } + + PlayerControl { + icon: "skip_next" + + function onClicked(): void { + if (Players.active?.canGoNext) + Players.active.next(); + } + } + } + } + + component PlayerControl: CustomRect { + id: control + + property alias animate: controlIcon.animate + property alias icon: controlIcon.text + property bool active + property string colour: "Secondary" + property int level: 1 + + function onClicked(): void { + } + + Layout.preferredWidth: implicitWidth + (controlState.pressed ? Appearance.padding.normal * 2 : active ? Appearance.padding.small * 2 : 0) + implicitWidth: controlIcon.implicitWidth + Appearance.padding.large * 2 + implicitHeight: controlIcon.implicitHeight + Appearance.padding.normal * 2 + + color: active ? DynamicColors.palette[`m3${colour.toLowerCase()}`] : DynamicColors.palette[`m3${colour.toLowerCase()}Container`] + radius: active || controlState.pressed ? Appearance.rounding.small : Appearance.rounding.normal + + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: controlState.containsMouse && !controlState.pressed ? control.level + 1 : control.level + } + + StateLayer { + id: controlState + + color: control.active ? DynamicColors.palette[`m3on${control.colour}`] : DynamicColors.palette[`m3on${control.colour}Container`] + + function onClicked(): void { + control.onClicked(); + } + } + + MaterialIcon { + id: controlIcon + + anchors.centerIn: parent + color: control.active ? DynamicColors.palette[`m3on${control.colour}`] : DynamicColors.palette[`m3on${control.colour}Container`] + font.pointSize: Appearance.font.size.large + fill: control.active ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on radius { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/NotifDock.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/NotifDock.qml new file mode 100644 index 0000000..6fca53c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/NotifDock.qml @@ -0,0 +1,145 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config +import qs.Daemons + +ColumnLayout { + id: root + + required property var lock + + anchors.fill: parent + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.smaller + + CustomText { + Layout.fillWidth: true + text: NotifServer.list.length > 0 ? qsTr("%1 notification%2").arg(NotifServer.list.length).arg(NotifServer.list.length === 1 ? "" : "s") : qsTr("Notifications") + color: DynamicColors.palette.m3outline + font.family: Appearance.font.family.mono + font.weight: 500 + elide: Text.ElideRight + } + + ClippingRectangle { + id: clipRect + + Layout.fillWidth: true + Layout.fillHeight: true + + radius: Appearance.rounding.small + color: "transparent" + + Loader { + anchors.centerIn: parent + active: opacity > 0 + opacity: NotifServer.list.length > 0 ? 0 : 1 + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.large + + Image { + asynchronous: true + source: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/dino.png`) + fillMode: Image.PreserveAspectFit + sourceSize.width: clipRect.width * 0.8 + + layer.enabled: true + layer.effect: Coloriser { + colorizationColor: DynamicColors.palette.m3outlineVariant + brightness: 1 + } + } + + CustomText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("No Notifications") + color: DynamicColors.palette.m3outlineVariant + font.pointSize: Appearance.font.size.large + font.family: Appearance.font.family.mono + font.weight: 500 + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.extraLarge + } + } + } + + CustomListView { + anchors.fill: parent + + spacing: Appearance.spacing.small + clip: true + + model: ScriptModel { + values: { + const list = NotifServer.notClosed.map(n => [n.appName, null]); + return [...new Map(list).keys()]; + } + } + + delegate: NotifGroup {} + + add: Transition { + Anim { + property: "opacity" + from: 0 + to: 1 + } + Anim { + property: "scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + remove: Transition { + Anim { + property: "opacity" + to: 0 + } + Anim { + property: "scale" + to: 0.6 + } + } + + move: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + Anim { + property: "y" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + displaced: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + Anim { + property: "y" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/NotifGroup.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/NotifGroup.qml new file mode 100644 index 0000000..9c74445 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/NotifGroup.qml @@ -0,0 +1,316 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config +import qs.Daemons + +CustomRect { + id: root + + required property string modelData + + readonly property list notifs: NotifServer.list.filter(notif => notif.appName === modelData) + readonly property string image: notifs.find(n => n.image.length > 0)?.image ?? "" + readonly property string appIcon: notifs.find(n => n.appIcon.length > 0)?.appIcon ?? "" + readonly property string urgency: notifs.some(n => n.urgency === NotificationUrgency.Critical) ? "critical" : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? "normal" : "low" + + property bool expanded + + anchors.left: parent?.left + anchors.right: parent?.right + implicitHeight: content.implicitHeight + Appearance.padding.normal * 2 + + clip: true + radius: Appearance.rounding.normal + color: root.urgency === "critical" ? DynamicColors.palette.m3secondaryContainer : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) + + RowLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + Item { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + + Component { + id: imageComp + + Image { + source: Qt.resolvedUrl(root.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + width: Config.notifs.sizes.image + height: Config.notifs.sizes.image + } + } + + Component { + id: appIconComp + + ColoredIcon { + implicitSize: Math.round(Config.notifs.sizes.image * 0.6) + source: Quickshell.iconPath(root.appIcon) + color: root.urgency === "critical" ? DynamicColors.palette.m3onError : root.urgency === "low" ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + + Component { + id: materialIconComp + + MaterialIcon { + text: Icons.getNotifIcon(root.notifs[0]?.summary, root.urgency) + color: root.urgency === "critical" ? DynamicColors.palette.m3onError : root.urgency === "low" ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } + + ClippingRectangle { + anchors.fill: parent + color: root.urgency === "critical" ? DynamicColors.palette.m3error : root.urgency === "low" ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 3) : DynamicColors.palette.m3secondaryContainer + radius: Appearance.rounding.full + + Loader { + anchors.centerIn: parent + sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp + } + } + + Loader { + anchors.right: parent.right + anchors.bottom: parent.bottom + active: root.appIcon && root.image + + sourceComponent: CustomRect { + implicitWidth: Config.notifs.sizes.badge + implicitHeight: Config.notifs.sizes.badge + + color: root.urgency === "critical" ? DynamicColors.palette.m3error : root.urgency === "low" ? DynamicColors.palette.m3surfaceContainerHighest : DynamicColors.palette.m3secondaryContainer + radius: Appearance.rounding.full + + ColoredIcon { + anchors.centerIn: parent + implicitSize: Math.round(Config.notifs.sizes.badge * 0.6) + source: Quickshell.iconPath(root.appIcon) + color: root.urgency === "critical" ? DynamicColors.palette.m3onError : root.urgency === "low" ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + } + } + + ColumnLayout { + Layout.topMargin: -Appearance.padding.small + Layout.bottomMargin: -Appearance.padding.small / 2 - (root.expanded ? 0 : spacing) + Layout.fillWidth: true + spacing: Math.round(Appearance.spacing.small / 2) + + RowLayout { + Layout.bottomMargin: -parent.spacing + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + CustomText { + Layout.fillWidth: true + text: root.modelData + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + } + + CustomText { + animate: true + text: root.notifs[0]?.timeStr ?? "" + color: DynamicColors.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + CustomRect { + implicitWidth: expandBtn.implicitWidth + Appearance.padding.smaller * 2 + implicitHeight: groupCount.implicitHeight + Appearance.padding.small + + color: root.urgency === "critical" ? DynamicColors.palette.m3error : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2) + radius: Appearance.rounding.full + + opacity: root.notifs.length > Config.notifs.groupPreviewNum ? 1 : 0 + Layout.preferredWidth: root.notifs.length > Config.notifs.groupPreviewNum ? implicitWidth : 0 + + StateLayer { + color: root.urgency === "critical" ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface + + function onClicked(): void { + root.expanded = !root.expanded; + } + } + + RowLayout { + id: expandBtn + + anchors.centerIn: parent + spacing: Appearance.spacing.small / 2 + + CustomText { + id: groupCount + + Layout.leftMargin: Appearance.padding.small / 2 + animate: true + text: root.notifs.length + color: root.urgency === "critical" ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface + font.pointSize: Appearance.font.size.small + } + + MaterialIcon { + Layout.rightMargin: -Appearance.padding.small / 2 + animate: true + text: root.expanded ? "expand_less" : "expand_more" + color: root.urgency === "critical" ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on Layout.preferredWidth { + Anim {} + } + } + } + + Repeater { + model: ScriptModel { + values: root.notifs.slice(0, Config.notifs.groupPreviewNum) + } + + NotifLine { + id: notif + + ParallelAnimation { + running: true + + Anim { + target: notif + property: "opacity" + from: 0 + to: 1 + } + Anim { + target: notif + property: "scale" + from: 0.7 + to: 1 + } + Anim { + target: notif.Layout + property: "preferredHeight" + from: 0 + to: notif.implicitHeight + } + } + + ParallelAnimation { + running: notif.modelData.closed + onFinished: notif.modelData.unlock(notif) + + Anim { + target: notif + property: "opacity" + to: 0 + } + Anim { + target: notif + property: "scale" + to: 0.7 + } + Anim { + target: notif.Layout + property: "preferredHeight" + to: 0 + } + } + } + } + + Loader { + Layout.fillWidth: true + + opacity: root.expanded ? 1 : 0 + Layout.preferredHeight: root.expanded ? implicitHeight : 0 + active: opacity > 0 + + sourceComponent: ColumnLayout { + Repeater { + model: ScriptModel { + values: root.notifs.slice(Config.notifs.groupPreviewNum) + } + + NotifLine {} + } + } + + Behavior on opacity { + Anim {} + } + } + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + component NotifLine: CustomText { + id: notifLine + + required property NotifServer.Notif modelData + + Layout.fillWidth: true + textFormat: Text.MarkdownText + text: { + const summary = modelData.summary.replace(/\n/g, " "); + const body = modelData.body.replace(/\n/g, " "); + const color = root.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline; + + if (metrics.text === metrics.elidedText) + return `${summary} ${body}`; + + const t = metrics.elidedText.length - 3; + if (t < summary.length) + return `${summary.slice(0, t)}...`; + + return `${summary} ${body.slice(0, t - summary.length)}...`; + } + color: root.urgency === "critical" ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface + + Component.onCompleted: modelData.lock(this) + Component.onDestruction: modelData.unlock(this) + + TextMetrics { + id: metrics + + text: `${notifLine.modelData.summary} ${notifLine.modelData.body}`.replace(/\n/g, " ") + font.pointSize: notifLine.font.pointSize + font.family: notifLine.font.family + elideWidth: notifLine.width + elide: Text.ElideRight + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Pam.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Pam.qml new file mode 100644 index 0000000..9009b83 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Pam.qml @@ -0,0 +1,193 @@ +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Services.Pam +import QtQuick +import qs.Config + +Scope { + id: root + + required property WlSessionLock lock + + readonly property alias passwd: passwd + readonly property alias fprint: fprint + property string lockMessage + property string state + property string fprintState + property string buffer + + signal flashMsg + + function handleKey(event: KeyEvent): void { + if (passwd.active || state === "max") + return; + + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { + passwd.start(); + } else if (event.key === Qt.Key_Backspace) { + if (event.modifiers & Qt.ControlModifier) { + buffer = ""; + } else { + buffer = buffer.slice(0, -1); + } + } else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) { + // No illegal characters (you are insane if you use unicode in your password) + buffer += event.text; + } + } + + PamContext { + id: passwd + + config: "passwd" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onMessageChanged: { + if (message.startsWith("The account is locked")) + root.lockMessage = message; + else if (root.lockMessage && message.endsWith(" left to unlock)")) + root.lockMessage += "\n" + message; + } + + onResponseRequiredChanged: { + if (!responseRequired) + return; + + respond(root.buffer); + root.buffer = ""; + } + + onCompleted: res => { + if (res === PamResult.Success) + return root.lock.unlock(); + + if (res === PamResult.Error) + root.state = "error"; + else if (res === PamResult.MaxTries) + root.state = "max"; + else if (res === PamResult.Failed) + root.state = "fail"; + + root.flashMsg(); + stateReset.restart(); + } + } + + PamContext { + id: fprint + + property bool available + property int tries + property int errorTries + + function checkAvail(): void { + if (!available || !Config.lock.enableFprint || !root.lock.secure) { + abort(); + return; + } + + tries = 0; + errorTries = 0; + start(); + } + + config: "fprint" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onCompleted: res => { + if (!available) + return; + + if (res === PamResult.Success) + return root.lock.unlock(); + + if (res === PamResult.Error) { + root.fprintState = "error"; + errorTries++; + if (errorTries < 5) { + abort(); + errorRetry.restart(); + } + } else if (res === PamResult.MaxTries) { + // Isn't actually the real max tries as pam only reports completed + // when max tries is reached. + tries++; + if (tries < Config.lock.maxFprintTries) { + // Restart if not actually real max tries + root.fprintState = "fail"; + start(); + } else { + root.fprintState = "max"; + abort(); + } + } + + root.flashMsg(); + fprintStateReset.start(); + } + } + + Process { + id: availProc + + command: ["sh", "-c", "fprintd-list $USER"] + onExited: code => { + fprint.available = code === 0; + fprint.checkAvail(); + } + } + + Timer { + id: errorRetry + + interval: 800 + onTriggered: fprint.start() + } + + Timer { + id: stateReset + + interval: 4000 + onTriggered: { + if (root.state !== "max") + root.state = ""; + } + } + + Timer { + id: fprintStateReset + + interval: 4000 + onTriggered: { + root.fprintState = ""; + fprint.errorTries = 0; + } + } + + Connections { + target: root.lock + + function onSecureChanged(): void { + if (root.lock.secure) { + availProc.running = true; + root.buffer = ""; + root.state = ""; + root.fprintState = ""; + root.lockMessage = ""; + } + } + + function onUnlock(): void { + fprint.abort(); + } + } + + Connections { + target: Config.lock + + function onEnableFprintChanged(): void { + fprint.checkAvail(); + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Resources.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Resources.qml new file mode 100644 index 0000000..3eaa2d7 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/Resources.qml @@ -0,0 +1,80 @@ +import QtQuick +import QtQuick.Layouts +import qs.Modules +import qs.Components +import qs.Helpers +import qs.Config + +GridLayout { + id: root + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large + + rowSpacing: Appearance.spacing.large + columnSpacing: Appearance.spacing.large + rows: 1 + columns: 2 + + Ref { + service: SystemUsage + } + + Resource { + Layout.bottomMargin: Appearance.padding.large + Layout.topMargin: Appearance.padding.large + icon: "memory" + value: SystemUsage.cpuPerc + colour: DynamicColors.palette.m3primary + } + + Resource { + Layout.bottomMargin: Appearance.padding.large + Layout.topMargin: Appearance.padding.large + icon: "memory_alt" + value: SystemUsage.memPerc + colour: DynamicColors.palette.m3secondary + } + + component Resource: CustomRect { + id: res + + required property string icon + required property real value + required property color colour + + Layout.fillWidth: true + implicitHeight: width + + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.large + + CircularProgress { + id: circ + + anchors.fill: parent + value: res.value + padding: Appearance.padding.large * 3 + fgColour: res.colour + bgColour: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 3) + strokeWidth: width < 200 ? Appearance.padding.smaller : Appearance.padding.normal + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: res.icon + color: res.colour + font.pointSize: (circ.arcRadius * 0.7) || 1 + font.weight: 600 + } + + Behavior on value { + Anim { + duration: Appearance.anim.durations.large + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/UserImage.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/UserImage.qml new file mode 100644 index 0000000..987fefe --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/UserImage.qml @@ -0,0 +1,24 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import qs.Paths + +Item { + id: root + + ClippingRectangle { + radius: 1000 + anchors.fill: parent + Image { + id: userImage + + anchors.fill: parent + + sourceSize.width: parent.width + sourceSize.height: parent.height + asynchronous: true + fillMode: Image.PreserveAspectCrop + source: `${Paths.home}/.face` + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/WeatherInfo.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/WeatherInfo.qml new file mode 100644 index 0000000..b7c8e77 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Lock/WeatherInfo.qml @@ -0,0 +1,175 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Helpers +import qs.Config + +ColumnLayout { + id: root + + required property int rootHeight + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large * 2 + + spacing: Appearance.spacing.small + + Loader { + Layout.topMargin: Appearance.padding.large * 2 + Layout.bottomMargin: -Appearance.padding.large + Layout.alignment: Qt.AlignHCenter + + active: root.rootHeight > 610 + visible: active + + sourceComponent: CustomText { + text: qsTr("Weather") + color: DynamicColors.palette.m3primary + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.large + + MaterialIcon { + animate: true + text: Weather.icon + color: DynamicColors.palette.m3secondary + font.pointSize: Appearance.font.size.extraLarge * 2.5 + } + + ColumnLayout { + spacing: Appearance.spacing.small + + CustomText { + Layout.fillWidth: true + + animate: true + text: Weather.description + color: DynamicColors.palette.m3secondary + font.pointSize: Appearance.font.size.large + font.weight: 500 + elide: Text.ElideRight + } + + CustomText { + Layout.fillWidth: true + + animate: true + text: qsTr("Humidity: %1%").arg(Weather.humidity) + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + } + + Loader { + Layout.rightMargin: Appearance.padding.smaller + active: root.width > 400 + visible: active + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.small + + CustomText { + Layout.fillWidth: true + + animate: true + text: Weather.temp + color: DynamicColors.palette.m3primary + horizontalAlignment: Text.AlignRight + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + elide: Text.ElideLeft + } + + CustomText { + Layout.fillWidth: true + + animate: true + text: qsTr("Feels like: %1").arg(Weather.feelsLike) + color: DynamicColors.palette.m3outline + horizontalAlignment: Text.AlignRight + font.pointSize: Appearance.font.size.smaller + elide: Text.ElideLeft + } + } + } + } + + Loader { + id: forecastLoader + + Layout.topMargin: Appearance.spacing.smaller + Layout.bottomMargin: Appearance.padding.large * 2 + Layout.fillWidth: true + + active: root.rootHeight > 820 + visible: active + + sourceComponent: RowLayout { + spacing: Appearance.spacing.large + + Repeater { + model: { + const forecast = Weather.hourlyForecast; + const count = root.width < 320 ? 3 : root.width < 400 ? 4 : 5; + if (!forecast) + return Array.from({ + length: count + }, () => null); + + return forecast.slice(0, count); + } + + ColumnLayout { + id: forecastHour + + required property var modelData + + Layout.fillWidth: true + spacing: Appearance.spacing.small + + CustomText { + Layout.fillWidth: true + text: { + const hour = forecastHour.modelData?.hour ?? 0; + return hour > 12 ? `${(hour - 12).toString().padStart(2, "0")} PM` : `${hour.toString().padStart(2, "0")} AM`; + } + color: DynamicColors.palette.m3outline + horizontalAlignment: Text.AlignHCenter + font.pointSize: Appearance.font.size.larger + } + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: forecastHour.modelData?.icon ?? "cloud_alert" + font.pointSize: Appearance.font.size.extraLarge * 1.5 + font.weight: 500 + } + + CustomText { + Layout.alignment: Qt.AlignHCenter + text: Config.services.useFahrenheit ? `${forecastHour.modelData?.tempF ?? 0}°F` : `${forecastHour.modelData?.tempC ?? 0}°C` + color: DynamicColors.palette.m3secondary + font.pointSize: Appearance.font.size.larger + } + } + } + } + } + + Timer { + running: true + triggeredOnStart: true + repeat: true + interval: 900000 // 15 minutes + onTriggered: Weather.reload() + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Network/NetworkPopout.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Network/NetworkPopout.qml new file mode 100644 index 0000000..e9bcd6a --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Network/NetworkPopout.qml @@ -0,0 +1,38 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Networking +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Modules +import qs.Helpers as Helpers + +Item { + id: root + + required property var wrapper + + Component.onCompleted: console.log(Networking.backend.toString()) + + ColumnLayout { + id: layout + + spacing: 8 + + Repeater { + model: Helpers.Network.devices + + CustomRadioButton { + id: network + visible: modelData.name !== "lo" + + required property NetworkDevice modelData + + checked: Helpers.Network.activeDevice?.name === modelData.name + text: modelData.description + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Network/NetworkWidget.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Network/NetworkWidget.qml new file mode 100644 index 0000000..ac1e378 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Network/NetworkWidget.qml @@ -0,0 +1,25 @@ +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules + +Item { + id: root + + anchors.top: parent.top + anchors.bottom: parent.bottom + + implicitWidth: layout.implicitWidth + + RowLayout { + id: layout + anchors.top: parent.top + anchors.bottom: parent.bottom + + MaterialIcon { + text: "android_wifi_4_bar" + Layout.alignment: Qt.AlignVCenter + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/NotifBell.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/NotifBell.qml new file mode 100644 index 0000000..3f43d1e --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/NotifBell.qml @@ -0,0 +1,48 @@ +import Quickshell +import Quickshell.Hyprland +import QtQuick +import qs.Config +import qs.Helpers +import qs.Components + +Item { + id: root + + required property PersistentProperties visibilities + required property Wrapper popouts + + implicitWidth: 25 + anchors.top: parent.top + anchors.bottom: parent.bottom + + CustomRect { + anchors.fill: parent + anchors.topMargin: 3 + anchors.bottomMargin: 3 + color: "transparent" + radius: 4 + MaterialIcon { + id: notificationCenterIcon + + anchors.centerIn: parent + + property color iconColor: DynamicColors.palette.m3onSurface + + text: HasNotifications.hasNotifications ? "\uf4fe" : "\ue7f4" + font.family: "Material Symbols Rounded" + font.pixelSize: 20 + color: iconColor + + Behavior on color { + CAnim {} + } + } + + StateLayer { + cursorShape: Qt.PointingHandCursor + onClicked: { + root.visibilities.sidebar = !root.visibilities.sidebar; + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Background.qml new file mode 100644 index 0000000..54af8d1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Background.qml @@ -0,0 +1,53 @@ +import qs.Components +import qs.Config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + required property var sidebar + readonly property real rounding: 8 + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: DynamicColors.palette.m3surface + + PathLine { + relativeX: -(root.wrapper.width + root.rounding) + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + PathArc { + relativeX: root.sidebar.notifsRoundingX + relativeY: root.roundingY + radiusX: root.sidebar.notifsRoundingX + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.notifsRoundingX : root.wrapper.width + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: root.rounding + radiusX: root.rounding + radiusY: root.rounding + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Content.qml new file mode 100644 index 0000000..90447c9 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Content.qml @@ -0,0 +1,203 @@ +import qs.Components +import qs.Config +import qs.Daemons +import Quickshell +import Quickshell.Widgets +import QtQuick + +Item { + id: root + + required property PersistentProperties visibilities + required property Item panels + readonly property int padding: 6 + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: Config.notifs.sizes.width + padding * 2 + implicitHeight: { + const count = list.count; + if (count === 0) + return 0; + + let height = (count - 1) * 8; + for (let i = 0; i < count; i++) + height += list.itemAtIndex(i)?.nonAnimHeight ?? 0; + + if (visibilities && panels) { + if (visibilities.osd) { + const h = panels.osd.y - 8 * 2 - padding * 2; + if (height > h) + height = h; + } + + if (visibilities.session) { + const h = panels.session.y - 8 * 2 - padding * 2; + if (height > h) + height = h; + } + } + + return Math.min((QsWindow.window?.screen?.height ?? 0) - 1 * 2, height + padding * 2); + } + + ClippingWrapperRectangle { + anchors.fill: parent + anchors.margins: root.padding + + color: "transparent" + radius: 4 + + CustomListView { + id: list + + model: ScriptModel { + values: NotifServer.popups.filter(n => !n.closed) + } + + anchors.fill: parent + + orientation: Qt.Vertical + spacing: 0 + cacheBuffer: QsWindow.window?.screen.height ?? 0 + + delegate: Item { + id: wrapper + + required property NotifServer.Notif modelData + required property int index + readonly property alias nonAnimHeight: notif.nonAnimHeight + property int idx + + onIndexChanged: { + if (index !== -1) + idx = index; + } + + implicitWidth: notif.implicitWidth + implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : 8) + + ListView.onRemove: removeAnim.start() + + SequentialAnimation { + id: removeAnim + + PropertyAction { + target: wrapper + property: "ListView.delayRemove" + value: true + } + PropertyAction { + target: wrapper + property: "enabled" + value: false + } + PropertyAction { + target: wrapper + property: "implicitHeight" + value: 0 + } + PropertyAction { + target: wrapper + property: "z" + value: 1 + } + Anim { + target: notif + property: "x" + to: (notif.x >= 0 ? Config.notifs.sizes.width : -Config.notifs.sizes.width) * 2 + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + PropertyAction { + target: wrapper + property: "ListView.delayRemove" + value: false + } + } + + ClippingRectangle { + anchors.top: parent.top + anchors.topMargin: wrapper.idx === 0 ? 0 : 8 + + color: "transparent" + radius: 4 + implicitWidth: notif.implicitWidth + implicitHeight: notif.implicitHeight + + Notification { + id: notif + + modelData: wrapper.modelData + } + } + } + + move: Transition { + Anim { + property: "y" + } + } + + displaced: Transition { + Anim { + property: "y" + } + } + + ExtraIndicator { + anchors.top: parent.top + extra: { + const count = list.count; + if (count === 0) + return 0; + + const scrollY = list.contentY; + + let height = 0; + for (let i = 0; i < count; i++) { + height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 8; + + if (height - 8 >= scrollY) + return i; + } + + return count; + } + } + + ExtraIndicator { + anchors.bottom: parent.bottom + extra: { + const count = list.count; + if (count === 0) + return 0; + + const scrollY = list.contentHeight - (list.contentY + list.height); + + let height = 0; + for (let i = count - 1; i >= 0; i--) { + height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 8; + + if (height - 8 >= scrollY) + return count - i - 1; + } + + return 0; + } + } + } + } + + Behavior on implicitHeight { + Anim {} + } + + component Anim: NumberAnimation { + easing.type: Easing.BezierSpline + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Notification.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Notification.qml new file mode 100644 index 0000000..fd94053 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Notification.qml @@ -0,0 +1,484 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Modules +import qs.Daemons +import qs.Helpers +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts + +CustomRect { + id: root + + required property NotifServer.Notif modelData + readonly property bool hasImage: modelData.image.length > 0 + readonly property bool hasAppIcon: modelData.appIcon.length > 0 + readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2 + property bool expanded: Config.notifs.openExpanded + + color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondaryContainer : DynamicColors.tPalette.m3surfaceContainer + radius: 6 + implicitWidth: Config.notifs.sizes.width + implicitHeight: inner.implicitHeight + + x: Config.notifs.sizes.width + Component.onCompleted: { + x = 0; + modelData.lock(this); + } + Component.onDestruction: modelData.unlock(this) + + Behavior on x { + Anim { + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + MouseArea { + property int startY + + anchors.fill: parent + hoverEnabled: true + cursorShape: root.expanded && body.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined + acceptedButtons: Qt.LeftButton | Qt.MiddleButton + preventStealing: true + + onEntered: root.modelData.timer.stop() + onExited: { + if (!pressed) + root.modelData.timer.start(); + } + + drag.target: parent + drag.axis: Drag.XAxis + + onPressed: event => { + root.modelData.timer.stop(); + startY = event.y; + if (event.button === Qt.MiddleButton) + root.modelData.close(); + } + onReleased: event => { + if (!containsMouse) + root.modelData.timer.start(); + + if (Math.abs(root.x) < Config.notifs.sizes.width * Config.notifs.clearThreshold) + root.x = 0; + else + root.modelData.popup = false; + } + onPositionChanged: event => { + if (pressed) { + const diffY = event.y - startY; + if (Math.abs(diffY) > Config.notifs.expandThreshold) + root.expanded = diffY > 0; + } + } + onClicked: event => { + if (!Config.notifs.actionOnClick || event.button !== Qt.LeftButton) + return; + + const actions = root.modelData.actions; + if (actions?.length === 1) + actions[0].invoke(); + } + + Item { + id: inner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 8 + + implicitHeight: root.nonAnimHeight + + Behavior on implicitHeight { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Loader { + id: image + + active: root.hasImage + + anchors.left: parent.left + anchors.top: parent.top + width: Config.notifs.sizes.image + height: Config.notifs.sizes.image + visible: root.hasImage || root.hasAppIcon + asynchronous: true + + sourceComponent: ClippingRectangle { + radius: 1000 + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + + Image { + anchors.fill: parent + source: Qt.resolvedUrl(root.modelData.image) + fillMode: Image.PreserveAspectCrop + mipmap: true + cache: false + asynchronous: true + } + } + } + + Loader { + id: appIcon + + active: root.hasAppIcon || !root.hasImage + + anchors.horizontalCenter: root.hasImage ? undefined : image.horizontalCenter + anchors.verticalCenter: root.hasImage ? undefined : image.verticalCenter + anchors.right: root.hasImage ? image.right : undefined + anchors.bottom: root.hasImage ? image.bottom : undefined + asynchronous: true + + sourceComponent: CustomRect { + radius: 1000 + color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2) : DynamicColors.palette.m3secondaryContainer + implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + + Loader { + id: icon + + active: root.hasAppIcon + + anchors.centerIn: parent + asynchronous: true + + width: Math.round(parent.width * 0.6) + height: Math.round(parent.width * 0.6) + + sourceComponent: CustomIcon { + anchors.fill: parent + source: Quickshell.iconPath(root.modelData.appIcon) + layer.enabled: root.modelData.appIcon.endsWith("symbolic") + } + } + + Loader { + active: !root.hasAppIcon + anchors.centerIn: parent + anchors.horizontalCenterOffset: -18 * 0.02 + anchors.verticalCenterOffset: 18 * 0.02 + asynchronous: true + + sourceComponent: MaterialIcon { + text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency) + + color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer + font.pointSize: 18 + } + } + } + } + + CustomText { + id: appName + + anchors.top: parent.top + anchors.left: image.right + anchors.leftMargin: 10 + + animate: true + text: appNameMetrics.elidedText + maximumLineCount: 1 + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 10 + + opacity: root.expanded ? 1 : 0 + + Behavior on opacity { + Anim {} + } + } + + TextMetrics { + id: appNameMetrics + + text: root.modelData.appName + font.family: appName.font.family + font.pointSize: appName.font.pointSize + elide: Text.ElideRight + elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - 7 * 3 + } + + CustomText { + id: summary + + anchors.top: parent.top + anchors.left: image.right + anchors.leftMargin: 10 + + animate: true + text: summaryMetrics.elidedText + maximumLineCount: 1 + height: implicitHeight + + states: State { + name: "expanded" + when: root.expanded + + PropertyChanges { + summary.maximumLineCount: undefined + } + + AnchorChanges { + target: summary + anchors.top: appName.bottom + } + } + + transitions: Transition { + PropertyAction { + target: summary + property: "maximumLineCount" + } + AnchorAnimation { + easing.type: Easing.BezierSpline + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on height { + Anim {} + } + } + + TextMetrics { + id: summaryMetrics + + text: root.modelData.summary + font.family: summary.font.family + font.pointSize: summary.font.pointSize + elide: Text.ElideRight + elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - 7 * 3 + } + + CustomText { + id: timeSep + + anchors.top: parent.top + anchors.left: summary.right + anchors.leftMargin: 7 + + text: "•" + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 10 + + states: State { + name: "expanded" + when: root.expanded + + AnchorChanges { + target: timeSep + anchors.left: appName.right + } + } + + transitions: Transition { + AnchorAnimation { + easing.type: Easing.BezierSpline + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + } + + CustomText { + id: time + + anchors.top: parent.top + anchors.left: timeSep.right + anchors.leftMargin: 7 + + animate: true + horizontalAlignment: Text.AlignLeft + text: root.modelData.timeStr + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 10 + } + + Item { + id: expandBtn + + anchors.right: parent.right + anchors.top: parent.top + + implicitWidth: expandIcon.height + implicitHeight: expandIcon.height + + StateLayer { + radius: 1000 + color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface + + function onClicked() { + root.expanded = !root.expanded; + } + } + + MaterialIcon { + id: expandIcon + + anchors.centerIn: parent + + animate: true + text: root.expanded ? "expand_less" : "expand_more" + font.pointSize: 13 + } + } + + CustomText { + id: bodyPreview + + anchors.left: summary.left + anchors.right: expandBtn.left + anchors.top: summary.bottom + anchors.rightMargin: 7 + + animate: true + textFormat: Text.MarkdownText + text: bodyPreviewMetrics.elidedText + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 10 + + opacity: root.expanded ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + TextMetrics { + id: bodyPreviewMetrics + + text: root.modelData.body + font.family: bodyPreview.font.family + font.pointSize: bodyPreview.font.pointSize + elide: Text.ElideRight + elideWidth: bodyPreview.width + } + + CustomText { + id: body + + anchors.left: summary.left + anchors.right: expandBtn.left + anchors.top: summary.bottom + anchors.rightMargin: 7 + + animate: true + textFormat: Text.MarkdownText + text: root.modelData.body + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 10 + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + height: text ? implicitHeight : 0 + + onLinkActivated: link => { + if (!root.expanded) + return; + + Quickshell.execDetached(["app2unit", "-O", "--", link]); + root.modelData.popup = false; + } + + opacity: root.expanded ? 1 : 0 + + Behavior on opacity { + Anim {} + } + } + + RowLayout { + id: actions + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: body.bottom + anchors.topMargin: 7 + + spacing: 10 + + opacity: root.expanded ? 1 : 0 + + Behavior on opacity { + Anim {} + } + + Action { + modelData: QtObject { + readonly property string text: qsTr("Close") + function invoke(): void { + root.modelData.close(); + } + } + } + + Repeater { + model: root.modelData.actions + + delegate: Component { + Action {} + } + } + } + } + } + + component Action: CustomRect { + id: action + + required property var modelData + + radius: 1000 + color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) + + Layout.preferredWidth: actionText.width + 8 * 2 + Layout.preferredHeight: actionText.height + 4 * 2 + implicitWidth: actionText.width + 8 * 2 + implicitHeight: actionText.height + 4 * 2 + + StateLayer { + radius: 1000 + color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSurface + + function onClicked(): void { + action.modelData.invoke(); + } + } + + CustomText { + id: actionText + + anchors.centerIn: parent + text: actionTextMetrics.elidedText + color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 10 + } + + TextMetrics { + id: actionTextMetrics + + text: action.modelData.text + font.family: actionText.font.family + font.pointSize: actionText.font.pointSize + elide: Text.ElideRight + elideWidth: { + const numActions = root.modelData.actions.length + 1; + return (inner.width - actions.spacing * (numActions - 1)) / numActions - 8 * 2; + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Background.qml new file mode 100644 index 0000000..710d4e5 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Background.qml @@ -0,0 +1,53 @@ +import qs.Components +import qs.Config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + required property var panels + + readonly property real rounding: 8 + + readonly property real notifsWidthDiff: panels.notifications.width - wrapper.width + readonly property real notifsRoundingX: panels.notifications.height > 0 && notifsWidthDiff < rounding * 2 ? notifsWidthDiff / 2 : rounding + + readonly property real utilsWidthDiff: panels.utilities.width - wrapper.width + readonly property real utilsRoundingX: utilsWidthDiff < rounding * 2 ? utilsWidthDiff / 2 : rounding + + readonly property bool flatten: wrapper.width < rounding * 2 + + strokeWidth: -1 + fillColor: flatten ? "transparent" : DynamicColors.palette.m3surface + + PathLine { + relativeX: -root.wrapper.width - root.notifsRoundingX + relativeY: 0 + } + PathArc { + relativeX: root.notifsRoundingX + relativeY: root.rounding + radiusX: root.notifsRoundingX + radiusY: root.rounding + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.rounding * 2 + } + PathArc { + relativeX: -root.utilsRoundingX + relativeY: root.rounding + radiusX: root.utilsRoundingX + radiusY: root.rounding + } + PathLine { + relativeX: root.wrapper.width + root.utilsRoundingX + relativeY: 0 + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Content.qml new file mode 100644 index 0000000..7465efc --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Content.qml @@ -0,0 +1,39 @@ +import qs.Components +import qs.Config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Props props + required property var visibilities + + ColumnLayout { + id: layout + + anchors.fill: parent + spacing: 8 + + CustomRect { + Layout.fillWidth: true + Layout.fillHeight: true + + radius: 8 + color: DynamicColors.tPalette.m3surfaceContainerLow + + NotifDock { + props: root.props + visibilities: root.visibilities + } + } + + CustomRect { + Layout.topMargin: 8 - layout.spacing + Layout.fillWidth: true + implicitHeight: 1 + + color: DynamicColors.tPalette.m3outlineVariant + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Notif.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Notif.qml new file mode 100644 index 0000000..5ef7a42 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Notif.qml @@ -0,0 +1,166 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Daemons +import qs.Modules +import Quickshell +import QtQuick +import QtQuick.Layouts + +CustomRect { + id: root + + required property NotifServer.Notif modelData + required property Props props + required property bool expanded + required property var visibilities + + readonly property CustomText body: expandedContent.item?.body ?? null + readonly property real nonAnimHeight: expanded ? summary.implicitHeight + expandedContent.implicitHeight + expandedContent.anchors.topMargin + 10 * 2 : summaryHeightMetrics.height + + implicitHeight: nonAnimHeight + + radius: 6 + color: { + const c = root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondaryContainer : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2); + return expanded ? c : Qt.alpha(c, 0); + } + + states: State { + name: "expanded" + when: root.expanded + + PropertyChanges { + summary.anchors.margins: 10 + dummySummary.anchors.margins: 10 + compactBody.anchors.margins: 10 + timeStr.anchors.margins: 10 + expandedContent.anchors.margins: 10 + summary.width: root.width - 10 * 2 - timeStr.implicitWidth - 7 + summary.maximumLineCount: Number.MAX_SAFE_INTEGER + } + } + + transitions: Transition { + Anim { + properties: "margins,width,maximumLineCount" + } + } + + TextMetrics { + id: summaryHeightMetrics + + font: summary.font + text: " " // Use this height to prevent weird characters from changing the line height + } + + CustomText { + id: summary + + anchors.top: parent.top + anchors.left: parent.left + + width: parent.width + text: root.modelData.summary + color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface + elide: Text.ElideRight + wrapMode: Text.WordWrap + maximumLineCount: 1 + } + + CustomText { + id: dummySummary + + anchors.top: parent.top + anchors.left: parent.left + + visible: false + text: root.modelData.summary + } + + WrappedLoader { + id: compactBody + + shouldBeActive: !root.expanded + anchors.top: parent.top + anchors.left: dummySummary.right + anchors.right: parent.right + anchors.leftMargin: 7 + + sourceComponent: CustomText { + textFormat: Text.StyledText + text: root.modelData.body.replace(/\n/g, " ") + color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline + elide: Text.ElideRight + } + } + + WrappedLoader { + id: timeStr + + shouldBeActive: root.expanded + anchors.top: parent.top + anchors.right: parent.right + + sourceComponent: CustomText { + animate: true + text: root.modelData.timeStr + color: DynamicColors.palette.m3outline + font.pointSize: 11 + } + } + + WrappedLoader { + id: expandedContent + + shouldBeActive: root.expanded + anchors.top: summary.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 7 / 2 + + sourceComponent: ColumnLayout { + readonly property alias body: body + + spacing: 10 + + CustomText { + id: body + + Layout.fillWidth: true + textFormat: Text.MarkdownText + text: root.modelData.body.replace(/(.)\n(?!\n)/g, "$1\n\n") || qsTr("No body given") + color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3onSurface + wrapMode: Text.WordWrap + + onLinkActivated: link => { + Quickshell.execDetached(["app2unit", "-O", "--", link]); + root.visibilities.sidebar = false; + } + } + + NotifActionList { + notif: root.modelData + } + } + } + + Behavior on implicitHeight { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + component WrappedLoader: Loader { + required property bool shouldBeActive + + opacity: shouldBeActive ? 1 : 0 + active: opacity > 0 + + Behavior on opacity { + Anim {} + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifActionList.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifActionList.qml new file mode 100644 index 0000000..fcfcff6 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifActionList.qml @@ -0,0 +1,134 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Modules +import qs.Daemons +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property NotifServer.Notif notif + + Layout.fillWidth: true + implicitHeight: flickable.contentHeight + + CustomFlickable { + id: flickable + + anchors.fill: parent + contentWidth: Math.max(width, actionList.implicitWidth) + contentHeight: actionList.implicitHeight + + RowLayout { + id: actionList + + anchors.fill: parent + spacing: 7 + + Repeater { + model: [ + { + isClose: true + }, + ...root.notif.actions, + { + isCopy: true + } + ] + + CustomRect { + id: action + + required property var modelData + + Layout.fillWidth: true + Layout.fillHeight: true + implicitWidth: actionInner.implicitWidth + 5 * 2 + implicitHeight: actionInner.implicitHeight + 5 * 2 + + Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? 18 : 0) + radius: actionStateLayer.pressed ? 6 / 2 : 6 + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 4) + + Timer { + id: copyTimer + + interval: 1000 + onTriggered: actionInner.item.text = "content_copy" + } + + StateLayer { + id: actionStateLayer + + function onClicked(): void { + if (action.modelData.isClose) { + root.notif.close(); + } else if (action.modelData.isCopy) { + Quickshell.clipboardText = root.notif.body; + actionInner.item.text = "inventory"; + copyTimer.start(); + } else if (action.modelData.invoke) { + action.modelData.invoke(); + } else if (!root.notif.resident) { + root.notif.close(); + } + } + } + + Loader { + id: actionInner + + anchors.centerIn: parent + sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif.hasActionIcons ? iconComp : textComp + } + + Component { + id: iconBtn + + MaterialIcon { + animate: action.modelData.isCopy ?? false + text: action.modelData.isCopy ? "content_copy" : "close" + color: DynamicColors.palette.m3onSurfaceVariant + } + } + + Component { + id: iconComp + + IconImage { + source: Quickshell.iconPath(action.modelData.identifier) + } + } + + Component { + id: textComp + + CustomText { + text: action.modelData.text + color: DynamicColors.palette.m3onSurfaceVariant + } + } + + Behavior on Layout.preferredWidth { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on radius { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifDock.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifDock.qml new file mode 100644 index 0000000..a97d4f5 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifDock.qml @@ -0,0 +1,192 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Modules +import qs.Daemons +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Props props + required property var visibilities + readonly property int notifCount: NotifServer.list.reduce((acc, n) => n.closed ? acc : acc + 1, 0) + + anchors.fill: parent + anchors.margins: 8 + + Component.onCompleted: NotifServer.list.forEach(n => n.popup = false) + + Item { + id: title + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 4 + + implicitHeight: Math.max(count.implicitHeight, titleText.implicitHeight) + + CustomText { + id: count + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: root.notifCount > 0 ? 0 : -width - titleText.anchors.leftMargin + opacity: root.notifCount > 0 ? 1 : 0 + + text: root.notifCount + color: DynamicColors.palette.m3outline + font.pointSize: 13 + font.family: "CaskaydiaCove NF" + font.weight: 500 + + Behavior on anchors.leftMargin { + Anim {} + } + + Behavior on opacity { + Anim {} + } + } + + CustomText { + id: titleText + + anchors.verticalCenter: parent.verticalCenter + anchors.left: count.right + anchors.right: parent.right + anchors.leftMargin: 7 + + text: root.notifCount > 0 ? qsTr("notification%1").arg(root.notifCount === 1 ? "" : "s") : qsTr("Notifications") + color: DynamicColors.palette.m3outline + font.pointSize: 13 + font.family: "CaskaydiaCove NF" + font.weight: 500 + elide: Text.ElideRight + } + } + + ClippingRectangle { + id: clipRect + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: title.bottom + anchors.bottom: parent.bottom + anchors.topMargin: 10 + + radius: 6 + color: "transparent" + + Loader { + anchors.centerIn: parent + active: opacity > 0 + opacity: root.notifCount > 0 ? 0 : 1 + + sourceComponent: ColumnLayout { + spacing: 20 + + CustomText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("No Notifications") + color: DynamicColors.palette.m3outlineVariant + font.pointSize: 18 + font.family: "CaskaydiaCove NF" + font.weight: 500 + } + } + + Behavior on opacity { + Anim { + duration: MaterialEasing.expressiveEffectsTime + } + } + } + + CustomFlickable { + id: view + + anchors.fill: parent + + flickableDirection: Flickable.VerticalFlick + contentWidth: width + contentHeight: notifList.implicitHeight + + CustomScrollBar.vertical: CustomScrollBar { + flickable: view + } + + NotifDockList { + id: notifList + + props: root.props + visibilities: root.visibilities + container: view + } + } + } + + Timer { + id: clearTimer + + repeat: true + interval: 50 + onTriggered: { + let next = null; + for (let i = 0; i < notifList.repeater.count; i++) { + next = notifList.repeater.itemAt(i); + if (!next?.closed) + break; + } + if (next) + next.closeAll(); + else + stop(); + } + } + + Loader { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 8 + + scale: root.notifCount > 0 ? 1 : 0.5 + opacity: root.notifCount > 0 ? 1 : 0 + active: opacity > 0 + + sourceComponent: IconButton { + id: clearBtn + + icon: "clear_all" + radius: 8 + padding: 8 + font.pointSize: Math.round(18 * 1.2) + onClicked: clearTimer.start() + + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: clearBtn.stateLayer.containsMouse ? 4 : 3 + } + } + + Behavior on scale { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on opacity { + Anim { + duration: MaterialEasing.expressiveEffectsTime + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifDockList.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifDockList.qml new file mode 100644 index 0000000..4c4d884 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifDockList.qml @@ -0,0 +1,169 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Modules +import qs.Daemons +import Quickshell +import QtQuick + +Item { + id: root + + required property Props props + required property Flickable container + required property var visibilities + + readonly property alias repeater: repeater + readonly property int spacing: 8 + property bool flag + + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: { + const item = repeater.itemAt(repeater.count - 1); + return item ? item.y + item.implicitHeight : 0; + } + + Repeater { + id: repeater + + model: ScriptModel { + values: { + const map = new Map(); + for (const n of NotifServer.notClosed) + map.set(n.appName, null); + for (const n of NotifServer.list) + map.set(n.appName, null); + return [...map.keys()]; + } + onValuesChanged: root.flagChanged() + } + + MouseArea { + id: notif + + required property int index + required property string modelData + + readonly property bool closed: notifInner.notifCount === 0 + readonly property alias nonAnimHeight: notifInner.nonAnimHeight + property int startY + + function closeAll(): void { + for (const n of NotifServer.notClosed.filter(n => n.appName === modelData)) { + n.close(); + } + } + + y: { + root.flag; // Force update + let y = 0; + for (let i = 0; i < index; i++) { + const item = repeater.itemAt(i); + if (!item.closed) + y += item.nonAnimHeight + root.spacing; + } + return y; + } + + containmentMask: QtObject { + function contains(p: point): bool { + if (!root.container.contains(notif.mapToItem(root.container, p))) + return false; + return notifInner.contains(p); + } + } + + implicitWidth: root.width + implicitHeight: notifInner.implicitHeight + + hoverEnabled: true + cursorShape: pressed ? Qt.ClosedHandCursor : undefined + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + preventStealing: true + enabled: !closed + + drag.target: this + drag.axis: Drag.XAxis + + onPressed: event => { + startY = event.y; + if (event.button === Qt.RightButton) + notifInner.toggleExpand(!notifInner.expanded); + else if (event.button === Qt.MiddleButton) + closeAll(); + } + onPositionChanged: event => { + if (pressed) { + const diffY = event.y - startY; + if (Math.abs(diffY) > Config.notifs.expandThreshold) + notifInner.toggleExpand(diffY > 0); + } + } + onReleased: event => { + if (Math.abs(x) < width * Config.notifs.clearThreshold) + x = 0; + else + closeAll(); + } + + ParallelAnimation { + running: true + + Anim { + target: notif + property: "opacity" + from: 0 + to: 1 + } + Anim { + target: notif + property: "scale" + from: 0 + to: 1 + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + ParallelAnimation { + running: notif.closed + + Anim { + target: notif + property: "opacity" + to: 0 + } + Anim { + target: notif + property: "scale" + to: 0.6 + } + } + + NotifGroup { + id: notifInner + + modelData: notif.modelData + props: root.props + container: root.container + visibilities: root.visibilities + } + + Behavior on x { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on y { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifGroup.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifGroup.qml new file mode 100644 index 0000000..cff822e --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifGroup.qml @@ -0,0 +1,239 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Modules +import qs.Daemons +import qs.Helpers +import Quickshell +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts + +CustomRect { + id: root + + required property string modelData + required property Props props + required property Flickable container + required property var visibilities + + readonly property list notifs: NotifServer.list.filter(n => n.appName === modelData) + readonly property int notifCount: notifs.reduce((acc, n) => n.closed ? acc : acc + 1, 0) + readonly property string image: notifs.find(n => !n.closed && n.image.length > 0)?.image ?? "" + readonly property string appIcon: notifs.find(n => !n.closed && n.appIcon.length > 0)?.appIcon ?? "" + readonly property int urgency: notifs.some(n => !n.closed && n.urgency === NotificationUrgency.Critical) ? NotificationUrgency.Critical : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? NotificationUrgency.Normal : NotificationUrgency.Low + + readonly property int nonAnimHeight: { + const headerHeight = header.implicitHeight + (root.expanded ? Math.round(7 / 2) : 0); + const columnHeight = headerHeight + notifList.nonAnimHeight + column.Layout.topMargin + column.Layout.bottomMargin; + return Math.round(Math.max(Config.notifs.sizes.image, columnHeight) + 10 * 2); + } + readonly property bool expanded: props.expandedNotifs.includes(modelData) + + function toggleExpand(expand: bool): void { + if (expand) { + if (!expanded) + props.expandedNotifs.push(modelData); + } else if (expanded) { + props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1); + } + } + + Component.onDestruction: { + if (notifCount === 0 && expanded) + props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1); + } + + anchors.left: parent?.left + anchors.right: parent?.right + implicitHeight: content.implicitHeight + 10 * 2 + + clip: true + radius: 8 + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2) + + RowLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 10 + + spacing: 10 + + Item { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + + Component { + id: imageComp + + Image { + source: Qt.resolvedUrl(root.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + width: Config.notifs.sizes.image + height: Config.notifs.sizes.image + } + } + + Component { + id: appIconComp + + CustomIcon { + implicitSize: Math.round(Config.notifs.sizes.image * 0.6) + source: Quickshell.iconPath(root.appIcon) + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + + Component { + id: materialIconComp + + MaterialIcon { + text: Icons.getNotifIcon(root.notifs[0]?.summary, root.urgency) + color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : root.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer + font.pointSize: 18 + } + } + + CustomClippingRect { + anchors.fill: parent + color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.urgency === NotificationUrgency.Low ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 3) : DynamicColors.palette.m3secondaryContainer + radius: 1000 + + Loader { + anchors.centerIn: parent + sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp + } + } + + Loader { + anchors.right: parent.right + anchors.bottom: parent.bottom + active: root.appIcon && root.image + + sourceComponent: CustomRect { + implicitWidth: Config.notifs.sizes.badge + implicitHeight: Config.notifs.sizes.badge + + color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3surfaceContainerHigh : DynamicColors.palette.m3secondaryContainer + radius: 1000 + + CustomIcon { + anchors.centerIn: parent + implicitSize: Math.round(Config.notifs.sizes.badge * 0.6) + source: Quickshell.iconPath(root.appIcon) + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + } + } + + ColumnLayout { + id: column + + Layout.topMargin: -10 + Layout.bottomMargin: -10 / 2 + Layout.fillWidth: true + spacing: 0 + + RowLayout { + id: header + + Layout.bottomMargin: root.expanded ? Math.round(7 / 2) : 0 + Layout.fillWidth: true + spacing: 5 + + CustomText { + Layout.fillWidth: true + text: root.modelData + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 11 + elide: Text.ElideRight + } + + CustomText { + animate: true + text: root.notifs.find(n => !n.closed)?.timeStr ?? "" + color: DynamicColors.palette.m3outline + font.pointSize: 11 + } + + CustomRect { + implicitWidth: expandBtn.implicitWidth + 7 * 2 + implicitHeight: groupCount.implicitHeight + 10 + + color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 3) + radius: 1000 + + StateLayer { + color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface + + function onClicked(): void { + root.toggleExpand(!root.expanded); + } + } + + RowLayout { + id: expandBtn + + anchors.centerIn: parent + spacing: 7 / 2 + + CustomText { + id: groupCount + + Layout.leftMargin: 10 / 2 + animate: true + text: root.notifCount + color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface + font.pointSize: 11 + } + + MaterialIcon { + Layout.rightMargin: -10 / 2 + text: "expand_more" + color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface + rotation: root.expanded ? 180 : 0 + Layout.topMargin: root.expanded ? -Math.floor(7 / 2) : 0 + + Behavior on rotation { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on Layout.topMargin { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + } + } + } + + Behavior on Layout.bottomMargin { + Anim {} + } + } + + NotifGroupList { + id: notifList + + props: root.props + notifs: root.notifs + expanded: root.expanded + container: root.container + visibilities: root.visibilities + onRequestToggleExpand: expand => root.toggleExpand(expand) + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifGroupList.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifGroupList.qml new file mode 100644 index 0000000..382f028 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/NotifGroupList.qml @@ -0,0 +1,214 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import qs.Modules +import qs.Daemons +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Props props + required property list notifs + required property bool expanded + required property Flickable container + required property var visibilities + + readonly property real nonAnimHeight: { + let h = -root.spacing; + for (let i = 0; i < repeater.count; i++) { + const item = repeater.itemAt(i); + if (!item.modelData.closed && !item.previewHidden) + h += item.nonAnimHeight + root.spacing; + } + return h; + } + + readonly property int spacing: Math.round(7 / 2) + property bool showAllNotifs + property bool flag + + signal requestToggleExpand(expand: bool) + + onExpandedChanged: { + if (expanded) { + clearTimer.stop(); + showAllNotifs = true; + } else { + clearTimer.start(); + } + } + + Layout.fillWidth: true + implicitHeight: nonAnimHeight + + Timer { + id: clearTimer + + interval: MaterialEasing.standardTime + onTriggered: root.showAllNotifs = false + } + + Repeater { + id: repeater + + model: ScriptModel { + values: root.showAllNotifs ? root.notifs : root.notifs.slice(0, Config.notifs.groupPreviewNum + 1) + onValuesChanged: root.flagChanged() + } + + MouseArea { + id: notif + + required property int index + required property NotifServer.Notif modelData + + readonly property alias nonAnimHeight: notifInner.nonAnimHeight + readonly property bool previewHidden: { + if (root.expanded) + return false; + + let extraHidden = 0; + for (let i = 0; i < index; i++) + if (root.notifs[i].closed) + extraHidden++; + + return index >= Config.notifs.groupPreviewNum + extraHidden; + } + property int startY + + y: { + root.flag; // Force update + let y = 0; + for (let i = 0; i < index; i++) { + const item = repeater.itemAt(i); + if (!item.modelData.closed && !item.previewHidden) + y += item.nonAnimHeight + root.spacing; + } + return y; + } + + containmentMask: QtObject { + function contains(p: point): bool { + if (!root.container.contains(notif.mapToItem(root.container, p))) + return false; + return notifInner.contains(p); + } + } + + opacity: previewHidden ? 0 : 1 + scale: previewHidden ? 0.7 : 1 + + implicitWidth: root.width + implicitHeight: notifInner.implicitHeight + + hoverEnabled: true + cursorShape: notifInner.body?.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + preventStealing: !root.expanded + enabled: !modelData.closed + + drag.target: this + drag.axis: Drag.XAxis + + onPressed: event => { + startY = event.y; + if (event.button === Qt.RightButton) + root.requestToggleExpand(!root.expanded); + else if (event.button === Qt.MiddleButton) + modelData.close(); + } + onPositionChanged: event => { + if (pressed && !root.expanded) { + const diffY = event.y - startY; + if (Math.abs(diffY) > Config.notifs.expandThreshold) + root.requestToggleExpand(diffY > 0); + } + } + onReleased: event => { + if (Math.abs(x) < width * Config.notifs.clearThreshold) + x = 0; + else + modelData.close(); + } + + Component.onCompleted: modelData.lock(this) + Component.onDestruction: modelData.unlock(this) + + ParallelAnimation { + Component.onCompleted: running = !notif.previewHidden + + Anim { + target: notif + property: "opacity" + from: 0 + to: 1 + } + Anim { + target: notif + property: "scale" + from: 0.7 + to: 1 + } + } + + ParallelAnimation { + running: notif.modelData.closed + onFinished: notif.modelData.unlock(notif) + + Anim { + target: notif + property: "opacity" + to: 0 + } + Anim { + target: notif + property: "x" + to: notif.x >= 0 ? notif.width : -notif.width + } + } + + Notif { + id: notifInner + + anchors.fill: parent + modelData: notif.modelData + props: root.props + expanded: root.expanded + visibilities: root.visibilities + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on x { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on y { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + } + } + + Behavior on implicitHeight { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Props.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Props.qml new file mode 100644 index 0000000..4613942 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Props.qml @@ -0,0 +1,7 @@ +import Quickshell + +PersistentProperties { + property list expandedNotifs: [] + + reloadableId: "sidebar" +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Background.qml new file mode 100644 index 0000000..875f35a --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Background.qml @@ -0,0 +1,54 @@ +import qs.Components +import qs.Config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + required property var sidebar + readonly property real rounding: 8 + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: DynamicColors.palette.m3surface + + PathLine { + relativeX: -(root.wrapper.width + root.rounding) + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: -(root.wrapper.height - root.roundingY * 2) + } + PathArc { + relativeX: root.sidebar.utilsRoundingX + relativeY: -root.roundingY + radiusX: root.sidebar.utilsRoundingX + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.utilsRoundingX : root.wrapper.width + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: -root.rounding + radiusX: root.rounding + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Cards/Toggles.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Cards/Toggles.qml new file mode 100644 index 0000000..d4d3821 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Cards/Toggles.qml @@ -0,0 +1,105 @@ +import Quickshell.Bluetooth +import Quickshell.Networking as QSNetwork +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Modules +import qs.Daemons + +CustomRect { + id: root + + required property var visibilities + required property Item popouts + + Layout.fillWidth: true + implicitHeight: layout.implicitHeight + 18 * 2 + + radius: 8 + color: DynamicColors.tPalette.m3surfaceContainer + + ColumnLayout { + id: layout + + anchors.fill: parent + anchors.margins: 18 + spacing: 10 + + RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: 7 + + Toggle { + visible: QSNetwork.Networking.devices.values.length > 0 + icon: Network.wifiEnabled ? "wifi" : "wifi_off" + checked: Network.wifiEnabled + onClicked: Network.toggleWifi() + } + + Toggle { + id: toggle + icon: NotifServer.dnd ? "notifications_off" : "notifications" + checked: !NotifServer.dnd + onClicked: NotifServer.dnd = !NotifServer.dnd + } + + Toggle { + icon: Audio.sourceMuted ? "mic_off" : "mic" + checked: !Audio.sourceMuted + onClicked: { + const audio = Audio.source?.audio; + if ( audio ) + audio.muted = !audio.muted; + } + } + + Toggle { + icon: Audio.muted ? "volume_off" : "volume_up" + checked: !Audio.muted + onClicked: { + const audio = Audio.sink?.audio; + if ( audio ) + audio.muted = !audio.muted; + } + } + + Toggle { + visible: Bluetooth.defaultAdapter ?? false + icon: Bluetooth.defaultAdapter?.enabled ? "bluetooth" : "bluetooth_disabled" + checked: Bluetooth.defaultAdapter?.enabled ?? false + onClicked: { + // console.log(Bluetooth.defaultAdapter) + const adapter = Bluetooth.defaultAdapter + if ( adapter ) + adapter.enabled = !adapter.enabled; + } + } + } + } + + CustomShortcut { + name: "toggle-dnd" + + onPressed: { + toggle.clicked(); + } + } + + component Toggle: IconButton { + Layout.fillWidth: true + Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? 18 : internalChecked ? 7 : 0) + radius: stateLayer.pressed ? 6 / 2 : internalChecked ? 6 : 8 + inactiveColour: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2) + toggle: true + radiusAnim.duration: MaterialEasing.expressiveEffectsTime + radiusAnim.easing.bezierCurve: MaterialEasing.expressiveEffects + + Behavior on Layout.preferredWidth { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Content.qml new file mode 100644 index 0000000..6508f47 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Content.qml @@ -0,0 +1,29 @@ +import qs.Modules.Notifications.Sidebar.Utils.Cards +import qs.Config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property var props + required property var visibilities + required property Item popouts + + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight + + ColumnLayout { + id: layout + + anchors.fill: parent + spacing: 8 + + IdleInhibit {} + + Toggles { + visibilities: root.visibilities + popouts: root.popouts + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/IdleInhibit.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/IdleInhibit.qml new file mode 100644 index 0000000..4595d1e --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/IdleInhibit.qml @@ -0,0 +1,124 @@ +import qs.Components +import qs.Config +import qs.Helpers +import QtQuick +import QtQuick.Layouts + +CustomRect { + id: root + + Layout.fillWidth: true + implicitHeight: layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2 + + radius: 8 + color: DynamicColors.tPalette.m3surfaceContainer + clip: true + + RowLayout { + id: layout + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 18 + spacing: 10 + + CustomRect { + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + 7 * 2 + + radius: 1000 + color: IdleInhibitor.enabled ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3secondaryContainer + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: "coffee" + color: IdleInhibitor.enabled ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSecondaryContainer + font.pointSize: 18 + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + CustomText { + Layout.fillWidth: true + text: qsTr("Keep Awake") + font.pointSize: 13 + elide: Text.ElideRight + } + + CustomText { + Layout.fillWidth: true + text: IdleInhibitor.enabled ? qsTr("Preventing sleep mode") : qsTr("Normal power management") + color: DynamicColors.palette.m3onSurfaceVariant + font.pointSize: 11 + elide: Text.ElideRight + } + } + + CustomSwitch { + checked: IdleInhibitor.enabled + onToggled: IdleInhibitor.enabled = checked + } + } + + Loader { + id: activeChip + + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.topMargin: 20 + anchors.bottomMargin: IdleInhibitor.enabled ? 18 : -implicitHeight + anchors.leftMargin: 18 + + opacity: IdleInhibitor.enabled ? 1 : 0 + scale: IdleInhibitor.enabled ? 1 : 0.5 + + Component.onCompleted: active = Qt.binding(() => opacity > 0) + + sourceComponent: CustomRect { + implicitWidth: activeText.implicitWidth + 10 * 2 + implicitHeight: activeText.implicitHeight + 10 * 2 + + radius: 1000 + color: DynamicColors.palette.m3primary + + CustomText { + id: activeText + + anchors.centerIn: parent + text: qsTr("Active since %1").arg(Qt.formatTime(IdleInhibitor.enabledSince, Config.services.useTwelveHourClock ? "hh:mm a" : "hh:mm")) + color: DynamicColors.palette.m3onPrimary + font.pointSize: Math.round(11 * 0.9) + } + } + + Behavior on anchors.bottomMargin { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on opacity { + Anim { + duration: MaterialEasing.expressiveEffectsTime + } + } + + Behavior on scale { + Anim {} + } + } + + Behavior on implicitHeight { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Wrapper.qml new file mode 100644 index 0000000..4f82920 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Utils/Wrapper.qml @@ -0,0 +1,96 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import Quickshell +import QtQuick + +Item { + id: root + + required property var visibilities + required property Item sidebar + required property Item popouts + + readonly property PersistentProperties props: PersistentProperties { + property bool recordingListExpanded: false + property string recordingConfirmDelete + property string recordingMode + + reloadableId: "utilities" + } + readonly property bool shouldBeActive: visibilities.sidebar + + visible: height > 0 + implicitHeight: 0 + implicitWidth: sidebar.visible ? sidebar.width : Config.utilities.sizes.width + + onStateChanged: { + if (state === "visible" && timer.running) { + timer.triggered(); + timer.stop(); + } + } + + states: State { + name: "visible" + when: root.shouldBeActive + + PropertyChanges { + root.implicitHeight: content.implicitHeight + 8 * 2 + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitHeight" + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitHeight" + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + ] + + Timer { + id: timer + + running: true + interval: 1000 + onTriggered: { + content.active = Qt.binding(() => root.shouldBeActive || root.visible); + content.visible = true; + } + } + + Loader { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 8 + + visible: false + active: true + + sourceComponent: Content { + implicitWidth: root.implicitWidth - 8 * 2 + props: root.props + visibilities: root.visibilities + popouts: root.popouts + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Wrapper.qml new file mode 100644 index 0000000..8a5de8b --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Sidebar/Wrapper.qml @@ -0,0 +1,68 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import QtQuick + +Item { + id: root + + required property var visibilities + required property var panels + readonly property Props props: Props {} + + visible: width > 0 + implicitWidth: 0 + + states: State { + name: "visible" + when: root.visibilities.sidebar + + PropertyChanges { + root.implicitWidth: Config.sidebar.sizes.width + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitWidth" + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + ] + + Loader { + id: content + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.margins: 8 + anchors.bottomMargin: 0 + + active: true + Component.onCompleted: active = Qt.binding(() => (root.visibilities.sidebar && Config.sidebar.enabled) || root.visible) + + sourceComponent: Content { + implicitWidth: Config.sidebar.sizes.width - 8 * 2 + props: root.props + visibilities: root.visibilities + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Wrapper.qml new file mode 100644 index 0000000..10d5729 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Notifications/Wrapper.qml @@ -0,0 +1,39 @@ +import QtQuick +import qs.Components +import qs.Config + +Item { + id: root + + required property var visibilities + required property Item panels + + visible: height > 0 + implicitWidth: Math.max(panels.sidebar.width, content.implicitWidth) + implicitHeight: content.implicitHeight + + states: State { + name: "hidden" + when: root.visibilities.sidebar + + PropertyChanges { + root.implicitHeight: 0 + } + } + + transitions: Transition { + Anim { + target: root + property: "implicitHeight" + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Content { + id: content + + visibilities: root.visibilities + panels: root.panels + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Background.qml new file mode 100644 index 0000000..b492d16 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Background.qml @@ -0,0 +1,59 @@ +import QtQuick +import QtQuick.Shapes +import qs.Components +import qs.Config + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: 10 + readonly property bool flatten: wrapper.width < rounding * 2 + readonly property real roundingX: flatten ? wrapper.width / 2 : rounding + + strokeWidth: -1 + fillColor: DynamicColors.palette.m3surface + + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + } + PathLine { + relativeX: -(root.wrapper.width - root.roundingX * 3) + relativeY: 0 + } + PathArc { + relativeX: -root.roundingX * 2 + relativeY: root.rounding * 2 + radiusX: Math.min(root.rounding * 2, root.wrapper.width) + radiusY: root.rounding * 2 + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.rounding * 4 + } + PathArc { + relativeX: root.roundingX * 2 + relativeY: root.rounding * 2 + radiusX: Math.min(root.rounding * 2, root.wrapper.width) + radiusY: root.rounding * 2 + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: root.wrapper.width - root.roundingX * 3 + relativeY: 0 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Content.qml new file mode 100644 index 0000000..15fc3a8 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Content.qml @@ -0,0 +1,136 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Helpers +import qs.Config +import qs.Daemons + +Item { + id: root + + required property Brightness.Monitor monitor + required property var visibilities + + required property real volume + required property bool muted + required property real sourceVolume + required property bool sourceMuted + required property real brightness + + implicitWidth: layout.implicitWidth + Appearance.padding.small * 2 + implicitHeight: layout.implicitHeight + Appearance.padding.small * 2 + + ColumnLayout { + id: layout + + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + // Speaker volume + CustomMouseArea { + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + + function onWheel(event: WheelEvent) { + if (event.angleDelta.y > 0) + Audio.incrementVolume(); + else if (event.angleDelta.y < 0) + Audio.decrementVolume(); + } + + FilledSlider { + anchors.fill: parent + + icon: Icons.getVolumeIcon(value, root.muted) + value: root.volume + to: Config.services.maxVolume + color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3secondary + onMoved: Audio.setVolume(value) + } + } + + // Microphone volume + WrappedLoader { + shouldBeActive: Config.osd.enableMicrophone && (!Config.osd.enableBrightness || !root.visibilities.session) + + sourceComponent: CustomMouseArea { + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + + function onWheel(event: WheelEvent) { + if (event.angleDelta.y > 0) + Audio.incrementSourceVolume(); + else if (event.angleDelta.y < 0) + Audio.decrementSourceVolume(); + } + + FilledSlider { + anchors.fill: parent + + icon: Icons.getMicVolumeIcon(value, root.sourceMuted) + value: root.sourceVolume + to: Config.services.maxVolume + color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3secondary + onMoved: Audio.setSourceVolume(value) + } + } + } + + // Brightness + WrappedLoader { + shouldBeActive: Config.osd.enableBrightness + + sourceComponent: CustomMouseArea { + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + + function onWheel(event: WheelEvent) { + const monitor = root.monitor; + if (!monitor) + return; + if (event.angleDelta.y > 0) + monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement); + else if (event.angleDelta.y < 0) + monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); + } + + FilledSlider { + anchors.fill: parent + + icon: `brightness_${(Math.round(value * 6) + 1)}` + value: root.brightness + onMoved: { + if ( Config.osd.allMonBrightness ) { + root.monitor?.setBrightness(value) + } else { + for (const mon of Brightness.monitors) { + mon.setBrightness(value) + } + } + } + } + } + } + } + + component WrappedLoader: Loader { + required property bool shouldBeActive + + Layout.preferredHeight: shouldBeActive ? Config.osd.sizes.sliderHeight : 0 + opacity: shouldBeActive ? 1 : 0 + active: opacity > 0 + visible: active + + Behavior on Layout.preferredHeight { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + Behavior on opacity { + Anim {} + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Wrapper.qml new file mode 100644 index 0000000..b8a52ea --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Osd/Wrapper.qml @@ -0,0 +1,135 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import qs.Components +import qs.Helpers +import qs.Config +import qs.Daemons + +Item { + id: root + + required property ShellScreen screen + required property var visibilities + property bool hovered + readonly property Brightness.Monitor monitor: Brightness.getMonitorForScreen(root.screen) + readonly property bool shouldBeActive: visibilities.osd && Config.osd.enabled && !(visibilities.utilities && Config.utilities.enabled) + + property real volume + property bool muted + property real sourceVolume + property bool sourceMuted + property real brightness + + function show(): void { + visibilities.osd = true; + timer.restart(); + } + + Component.onCompleted: { + volume = Audio.volume; + muted = Audio.muted; + sourceVolume = Audio.sourceVolume; + sourceMuted = Audio.sourceMuted; + brightness = root.monitor?.brightness ?? 0; + } + + visible: width > 0 + implicitWidth: 0 + implicitHeight: content.implicitHeight + + states: State { + name: "visible" + when: root.shouldBeActive + + PropertyChanges { + root.implicitWidth: content.implicitWidth + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: MaterialEasing.expressiveEffects + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + ] + + Connections { + target: Audio + + function onMutedChanged(): void { + root.show(); + root.muted = Audio.muted; + } + + function onVolumeChanged(): void { + root.show(); + root.volume = Audio.volume; + } + + function onSourceMutedChanged(): void { + root.show(); + root.sourceMuted = Audio.sourceMuted; + } + + function onSourceVolumeChanged(): void { + root.show(); + root.sourceVolume = Audio.sourceVolume; + } + } + + Connections { + target: root.monitor + + function onBrightnessChanged(): void { + root.show(); + root.brightness = root.monitor?.brightness ?? 0; + } + } + + Timer { + id: timer + + interval: Config.osd.hideDelay + onTriggered: { + if (!root.hovered) + root.visibilities.osd = false; + } + } + + Loader { + id: content + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + Component.onCompleted: active = Qt.binding(() => root.shouldBeActive || root.visible) + + sourceComponent: Content { + monitor: root.monitor + visibilities: root.visibilities + volume: root.volume + muted: root.muted + sourceVolume: root.sourceVolume + sourceMuted: root.sourceMuted + brightness: root.brightness + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Polkit/Polkit.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Polkit/Polkit.qml new file mode 100644 index 0000000..3f34ef5 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Polkit/Polkit.qml @@ -0,0 +1,352 @@ +import Quickshell +import Quickshell.Services.Polkit +import Quickshell.Wayland +import Quickshell.Hyprland +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import qs.Components +import qs.Modules +import qs.Config + +Scope { + id: root + + property alias polkitAgent: polkitAgent + property bool shouldShow: false + + PanelWindow { + id: panelWindow + + WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive + WlrLayershell.namespace: "ZShell-Auth" + WlrLayershell.layer: WlrLayer.Overlay + visible: false + color: "transparent" + property bool detailsOpen: false + + Connections { + target: root + + onShouldShowChanged: { + if ( root.shouldShow ) { + panelWindow.visible = true + openAnim.start() + } else { + closeAnim.start() + } + } + } + + Anim { + id: openAnim + target: inputPanel + property: "opacity" + to: 1 + duration: MaterialEasing.expressiveEffectsTime + } + + Anim { + id: closeAnim + target: inputPanel + property: "opacity" + to: 0 + duration: MaterialEasing.expressiveEffectsTime + onStarted: { + panelWindow.detailsOpen = false + } + onFinished: { + panelWindow.visible = false + } + } + + anchors { + left: true + right: true + top: true + bottom: true + } + + // mask: Region { item: inputPanel } + + Rectangle { + id: inputPanel + + color: DynamicColors.tPalette.m3surface + opacity: 0 + + anchors.centerIn: parent + radius: 24 + + implicitWidth: layout.childrenRect.width + 32 + implicitHeight: layout.childrenRect.height + 28 + ColumnLayout { + id: layout + anchors.centerIn: parent + + RowLayout { + id: contentRow + spacing: 24 + + Item { + Layout.preferredWidth: icon.implicitSize + Layout.preferredHeight: icon.implicitSize + Layout.leftMargin: 16 + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + IconImage { + id: icon + + anchors.fill: parent + visible: `${source}`.includes("://") + + source: Quickshell.iconPath(polkitAgent.flow?.iconName, true) ?? "" + implicitSize: 64 + mipmap: true + } + + MaterialIcon { + visible: !icon.visible + + text: "security" + anchors.fill: parent + font.pointSize: 64 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + ColumnLayout { + id: contentColumn + Layout.fillWidth: true + Layout.fillHeight: true + + CustomText { + Layout.preferredWidth: Math.min(600, contentWidth) + Layout.alignment: Qt.AlignLeft + + text: polkitAgent.flow?.message + wrapMode: Text.WordWrap + font.pointSize: 16 + font.bold: true + } + + CustomText { + Layout.preferredWidth: Math.min(600, contentWidth) + Layout.alignment: Qt.AlignLeft + + text: polkitAgent.flow?.supplementaryMessage || "No Additional Information" + color: DynamicColors.tPalette.m3onSurfaceVariant + wrapMode: Text.WordWrap + font.pointSize: 12 + font.bold: true + } + + TextField { + id: passInput + + echoMode: polkitAgent.flow?.responseVisible ? TextInput.Normal : TextInput.Password + placeholderText: polkitAgent.flow?.failed ? " Incorrect Password" : " Input Password" + selectByMouse: true + onAccepted: okButton.clicked() + + color: DynamicColors.palette.m3onSurfaceVariant + placeholderTextColor: polkitAgent.flow?.failed ? DynamicColors.palette.m3onError : DynamicColors.tPalette.m3onSurfaceVariant + + Layout.preferredWidth: contentColumn.implicitWidth + Layout.preferredHeight: 40 + + background: CustomRect { + radius: 8 + implicitHeight: 40 + color: ( polkitAgent.flow?.failed && passInput.text === "" ) ? DynamicColors.palette.m3error : DynamicColors.tPalette.m3surfaceVariant + } + } + + CustomCheckbox { + id: showPassCheckbox + text: "Show Password" + checked: polkitAgent.flow?.responseVisible + onCheckedChanged: { + passInput.echoMode = checked ? TextInput.Normal : TextInput.Password + passInput.forceActiveFocus() + } + + Layout.alignment: Qt.AlignLeft + } + } + } + + CustomRect { + id: detailsPanel + + visible: true + color: DynamicColors.tPalette.m3surfaceContainerLow + radius: 16 + clip: true + implicitHeight: 0 + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + + property bool open: panelWindow.detailsOpen + + Behavior on open { + ParallelAnimation { + Anim { + target: detailsPanel + + property: "implicitHeight" + to: !detailsPanel.open ? textDetailsColumn.childrenRect.height + 16 : 0 + duration: MaterialEasing.expressiveEffectsTime + } + + Anim { + target: textDetailsColumn + + property: "opacity" + to: !detailsPanel.open ? 1 : 0 + duration: MaterialEasing.expressiveEffectsTime + } + + Anim { + target: textDetailsColumn + + property: "scale" + to: !detailsPanel.open ? 1 : 0.9 + duration: MaterialEasing.expressiveEffectsTime + } + } + } + + ColumnLayout { + id: textDetailsColumn + spacing: 8 + anchors.fill: parent + anchors.margins: 8 + opacity: 0 + scale: 0.9 + + CustomText { + text: `actionId: ${polkitAgent.flow?.actionId}` + wrapMode: Text.WordWrap + } + + CustomText { + text: `selectedIdentity: ${polkitAgent.flow?.selectedIdentity}` + wrapMode: Text.WordWrap + } + } + } + + RowLayout { + spacing: 8 + Layout.preferredWidth: contentRow.implicitWidth + + CustomButton { + id: detailsButton + text: "Details" + textColor: DynamicColors.palette.m3onSurface + bgColor: DynamicColors.palette.m3surfaceContainer + enabled: true + radius: 1000 + + Layout.preferredWidth: 92 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignLeft + + onClicked: { + panelWindow.detailsOpen = !panelWindow.detailsOpen + console.log(panelWindow.detailsOpen) + } + } + + Item { + id: spacer + Layout.fillWidth: true + } + + CustomButton { + id: okButton + text: "OK" + textColor: DynamicColors.palette.m3onPrimary + bgColor: DynamicColors.palette.m3primary + enabled: passInput.text.length > 0 || !!polkitAgent.flow?.isResponseRequired + radius: 1000 + Layout.preferredWidth: 76 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignRight + onClicked: { + polkitAgent.flow.submit(passInput.text) + passInput.text = "" + passInput.forceActiveFocus() + } + } + + CustomButton { + id: cancelButton + text: "Cancel" + textColor: DynamicColors.palette.m3onSurface + bgColor: DynamicColors.palette.m3surfaceContainer + enabled: passInput.text.length > 0 || !!polkitAgent.flow?.isResponseRequired + radius: 1000 + Layout.preferredWidth: 76 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignRight + onClicked: { + root.shouldShow = false + console.log(icon.source, icon.visible) + polkitAgent.flow.cancelAuthenticationRequest() + passInput.text = "" + } + } + } + } + } + + Connections { + target: polkitAgent.flow + + function onIsResponseRequiredChanged() { + passInput.text = "" + if ( polkitAgent.flow?.isResponseRequired ) + root.shouldShow = true + passInput.forceActiveFocus() + } + + function onIsSuccessfulChanged() { + if ( polkitAgent.flow?.isSuccessful ) + root.shouldShow = false + passInput.text = "" + } + } + } + + PolkitAgent { + id: polkitAgent + } + + Variants { + model: Quickshell.screens + + PanelWindow { + + required property var modelData + + color: root.shouldShow ? "#80000000" : "transparent" + screen: modelData + exclusionMode: ExclusionMode.Ignore + visible: panelWindow.visible + + Behavior on color { + CAnim {} + } + + anchors { + left: true + right: true + top: true + bottom: true + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Resource.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Resource.qml new file mode 100644 index 0000000..4d888f0 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Resource.qml @@ -0,0 +1,110 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Shapes +import qs.Components +import qs.Config + +Item { + id: root + required property double percentage + property int warningThreshold: 100 + property bool shown: true + clip: true + visible: width > 0 && height > 0 + implicitWidth: resourceRowLayout.x < 0 ? 0 : resourceRowLayout.implicitWidth + implicitHeight: 22 + property bool warning: percentage * 100 >= warningThreshold + required property color mainColor + property color usageColor: warning ? DynamicColors.palette.m3error : mainColor + property color borderColor: warning ? DynamicColors.palette.m3onError : mainColor + + Behavior on percentage { + NumberAnimation { + duration: 300 + easing.type: Easing.InOutQuad + } + } + + RowLayout { + id: resourceRowLayout + spacing: 2 + x: shown ? 0 : -resourceRowLayout.width + anchors { + verticalCenter: parent.verticalCenter + } + + Item { + Layout.alignment: Qt.AlignVCenter + implicitWidth: 14 + implicitHeight: root.implicitHeight + + Rectangle { + id: backgroundCircle + anchors.centerIn: parent + width: 14 + height: 14 + radius: height / 2 + color: "#40000000" + border.color: "#404040" + border.width: 1 + } + + Shape { + anchors.fill: backgroundCircle + + smooth: true + preferredRendererType: Shape.CurveRenderer + + ShapePath { + strokeWidth: 0 + fillColor: root.usageColor + startX: backgroundCircle.width / 2 + startY: backgroundCircle.height / 2 + + Behavior on fillColor { + CAnim {} + } + + PathLine { + x: backgroundCircle.width / 2 + y: 0 + ( 1 / 2 ) + } + + PathAngleArc { + centerX: backgroundCircle.width / 2 + centerY: backgroundCircle.height / 2 + radiusX: backgroundCircle.width / 2 - ( 1 / 2 ) + radiusY: backgroundCircle.height / 2 - ( 1 / 2 ) + startAngle: -90 + sweepAngle: 360 * root.percentage + } + + PathLine { + x: backgroundCircle.width / 2 + y: backgroundCircle.height / 2 + } + } + + ShapePath { + strokeWidth: 1 + strokeColor: root.borderColor + fillColor: "transparent" + capStyle: ShapePath.FlatCap + + Behavior on strokeColor { + CAnim {} + } + + PathAngleArc { + centerX: backgroundCircle.width / 2 + centerY: backgroundCircle.height / 2 + radiusX: backgroundCircle.width / 2 - ( 1 / 2 ) + radiusY: backgroundCircle.height / 2 - ( 1 / 2 ) + startAngle: -90 + sweepAngle: 360 * root.percentage + } + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourceDetail.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourceDetail.qml new file mode 100644 index 0000000..9ceb6f0 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourceDetail.qml @@ -0,0 +1,75 @@ +import Quickshell +import QtQuick +import QtQuick.Layouts +import qs.Config +import qs.Components + +Item { + id: root + required property string resourceName + required property double percentage + required property int warningThreshold + required property string details + required property string iconString + property color barColor: DynamicColors.palette.m3primary + property color warningBarColor: DynamicColors.palette.m3error + property color textColor: DynamicColors.palette.m3onSurface + + Layout.preferredWidth: 158 + Layout.preferredHeight: columnLayout.implicitHeight + + ColumnLayout { + id: columnLayout + anchors.fill: parent + spacing: 4 + + Row { + spacing: 6 + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + + MaterialIcon { + font.family: "Material Symbols Rounded" + font.pointSize: 28 + text: root.iconString + color: root.textColor + } + + CustomText { + anchors.verticalCenter: parent.verticalCenter + text: root.resourceName + font.pointSize: 12 + color: root.textColor + } + } + + Rectangle { + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + Layout.preferredHeight: 6 + radius: height / 2 + color: "#40000000" + + Rectangle { + width: parent.width * Math.min(root.percentage, 1) + height: parent.height + radius: height / 2 + color: root.percentage * 100 >= root.warningThreshold ? root.warningBarColor : root.barColor + + Behavior on width { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + } + } + + CustomText { + Layout.alignment: Qt.AlignLeft + text: root.details + font.pointSize: 10 + color: root.textColor + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourcePopout.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourcePopout.qml new file mode 100644 index 0000000..c38d378 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourcePopout.qml @@ -0,0 +1,61 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Config + +Item { + id: popoutWindow + implicitWidth: contentColumn.implicitWidth + 10 * 2 + implicitHeight: contentColumn.implicitHeight + 10 + required property var wrapper + + // ShadowRect { + // anchors.fill: contentRect + // radius: 8 + // } + + ColumnLayout { + id: contentColumn + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + spacing: 10 + + ResourceDetail { + resourceName: qsTr( "Memory Usage" ) + iconString: "\uf7a3" + percentage: ResourceUsage.memoryUsedPercentage + warningThreshold: 95 + details: qsTr( "%1 of %2 MB used" ) + .arg( Math.round( ResourceUsage.memoryUsed * 0.001 )) + .arg( Math.round( ResourceUsage.memoryTotal * 0.001 )) + } + + ResourceDetail { + resourceName: qsTr( "CPU Usage" ) + iconString: "\ue322" + percentage: ResourceUsage.cpuUsage + warningThreshold: 95 + details: qsTr( "%1% used" ) + .arg( Math.round( ResourceUsage.cpuUsage * 100 )) + } + + ResourceDetail { + resourceName: qsTr( "GPU Usage" ) + iconString: "\ue30f" + percentage: ResourceUsage.gpuUsage + warningThreshold: 95 + details: qsTr( "%1% used" ) + .arg( Math.round( ResourceUsage.gpuUsage * 100 )) + } + + ResourceDetail { + resourceName: qsTr( "VRAM Usage" ) + iconString: "\ue30d" + percentage: ResourceUsage.gpuMemUsage + warningThreshold: 95 + details: qsTr( "%1% used" ) + .arg( Math.round( ResourceUsage.gpuMemUsage * 100 )) + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourceUsage.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourceUsage.qml new file mode 100644 index 0000000..415b8b0 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/ResourceUsage.qml @@ -0,0 +1,104 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import Quickshell.Io +import qs.Config + +Singleton { + id: root + property double memoryTotal: 1 + property double memoryFree: 1 + property double memoryUsed: memoryTotal - memoryFree + property double memoryUsedPercentage: memoryUsed / memoryTotal + property double swapTotal: 1 + property double swapFree: 1 + property double swapUsed: swapTotal - swapFree + property double swapUsedPercentage: swapTotal > 0 ? (swapUsed / swapTotal) : 0 + property double cpuUsage: 0 + property var previousCpuStats + property double gpuUsage: 0 + property double gpuMemUsage: 0 + property double totalMem: 0 + readonly property string gpuType: Config.services.gpuType.toUpperCase() || autoGpuType + property string autoGpuType: "NONE" + + Timer { + interval: 1 + running: true + repeat: true + onTriggered: { + // Reload files + fileMeminfo.reload() + fileStat.reload() + + // Parse memory and swap usage + const textMeminfo = fileMeminfo.text() + memoryTotal = Number(textMeminfo.match(/MemTotal: *(\d+)/)?.[1] ?? 1) + memoryFree = Number(textMeminfo.match(/MemAvailable: *(\d+)/)?.[1] ?? 0) + swapTotal = Number(textMeminfo.match(/SwapTotal: *(\d+)/)?.[1] ?? 1) + swapFree = Number(textMeminfo.match(/SwapFree: *(\d+)/)?.[1] ?? 0) + + // Parse CPU usage + const textStat = fileStat.text() + const cpuLine = textStat.match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) + if (cpuLine) { + const stats = cpuLine.slice(1).map(Number) + const total = stats.reduce((a, b) => a + b, 0) + const idle = stats[3] + + if (previousCpuStats) { + const totalDiff = total - previousCpuStats.total + const idleDiff = idle - previousCpuStats.idle + cpuUsage = totalDiff > 0 ? (1 - idleDiff / totalDiff) : 0 + } + + previousCpuStats = { total, idle } + } + if ( root.gpuType === "NVIDIA" ) { + processGpu.running = true + } + + interval = 3000 + } + } + + FileView { id: fileMeminfo; path: "/proc/meminfo" } + FileView { id: fileStat; path: "/proc/stat" } + + Process { + id: gpuTypeCheck + + running: !Config.services.gpuType + command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"] + stdout: StdioCollector { + onStreamFinished: root.autoGpuType = text.trim() + } + } + + Process { + id: oneshotMem + command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"] + running: root.gpuType === "NVIDIA" && totalMem === 0 + stdout: StdioCollector { + onStreamFinished: { + totalMem = Number(this.text.trim()) + oneshotMem.running = false + } + } + } + + Process { + id: processGpu + command: ["nvidia-smi", "--query-gpu=utilization.gpu,memory.used", "--format=csv,noheader,nounits"] + running: false + stdout: StdioCollector { + onStreamFinished: { + const parts = this.text.trim().split(", ") + gpuUsage = Number(parts[0]) / 100 + gpuMemUsage = Number(parts[1]) / totalMem + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Resources.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Resources.qml new file mode 100644 index 0000000..053246b --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Resources.qml @@ -0,0 +1,90 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import QtQuick.Layouts +import Quickshell.Wayland +import qs.Modules +import qs.Config +import qs.Effects +import qs.Components + +Item { + id: root + implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin + implicitHeight: 34 + clip: true + + Rectangle { + id: backgroundRect + anchors { + left: parent.left + right: parent.right + verticalCenter: parent.verticalCenter + } + implicitHeight: 22 + color: DynamicColors.tPalette.m3surfaceContainer + radius: height / 2 + Behavior on color { + CAnim {} + } + RowLayout { + id: rowLayout + + spacing: 6 + anchors.fill: parent + anchors.leftMargin: 5 + anchors.rightMargin: 5 + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: 18 + text: "memory_alt" + color: DynamicColors.palette.m3onSurface + } + + Resource { + percentage: ResourceUsage.memoryUsedPercentage + warningThreshold: 95 + mainColor: DynamicColors.palette.m3primary + } + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: 18 + text: "memory" + color: DynamicColors.palette.m3onSurface + } + + Resource { + percentage: ResourceUsage.cpuUsage + warningThreshold: 80 + mainColor: DynamicColors.palette.m3secondary + } + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: 18 + text: "gamepad" + color: DynamicColors.palette.m3onSurface + } + + Resource { + percentage: ResourceUsage.gpuUsage + mainColor: DynamicColors.palette.m3tertiary + } + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + font.pixelSize: 18 + text: "developer_board" + color: DynamicColors.palette.m3onSurface + } + + Resource { + percentage: ResourceUsage.gpuMemUsage + mainColor: DynamicColors.palette.m3primary + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Background.qml new file mode 100644 index 0000000..3218ffe --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Background.qml @@ -0,0 +1,66 @@ +import QtQuick +import QtQuick.Shapes +import qs.Components +import qs.Config +import qs.Helpers + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: 8 + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: DynamicColors.palette.m3surface + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min( root.roundingY, root.wrapper.height ) + } + + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min( root.rounding, root.wrapper.height ) + direction: PathArc.Counterclockwise + } + + PathLine { + relativeX: root.wrapper.width - root.rounding * 2 + relativeY: 0 + } + + PathArc { + relativeX: root.rounding + relativeY: - root.roundingY + radiusX: root.rounding + radiusY: Math.min( root.rounding, root.wrapper.height ) + direction: PathArc.Counterclockwise + } + + PathLine { + relativeX: 0 + relativeY: - ( root.wrapper.height - root.roundingY * 2 ) + } + + PathArc { + relativeX: root.rounding + relativeY: - root.roundingY + radiusX: root.rounding + radiusY: Math.min( root.rounding, root.wrapper.height ) + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories.qml new file mode 100644 index 0000000..a1d1ca1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories.qml @@ -0,0 +1,176 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +Item { + id: root + + required property Item content + + implicitWidth: clayout.implicitWidth + Appearance.padding.smaller * 2 + implicitHeight: clayout.implicitHeight + Appearance.padding.smaller * 2 + + CustomRect { + + anchors.fill: parent + + color: DynamicColors.tPalette.m3surfaceContainer + radius: 4 + + ColumnLayout { + id: clayout + + spacing: 5 + + anchors.centerIn: parent + + Category { + name: "General" + icon: "settings" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Wallpaper" + icon: "wallpaper" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Bar" + icon: "settop_component" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Lockscreen" + icon: "lock" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Services" + icon: "build_circle" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Notifications" + icon: "notifications" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Sidebar" + icon: "view_sidebar" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Utilities" + icon: "handyman" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Dashboard" + icon: "dashboard" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Appearance" + icon: "colors" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "On screen display" + icon: "display_settings" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Launcher" + icon: "rocket_launch" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + + Category { + name: "Colors" + icon: "colors" + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + } + } + } + + component Category: CustomRect { + id: categoryItem + + required property string name + required property string icon + + implicitWidth: 200 + implicitHeight: 42 + radius: 4 + + RowLayout { + id: layout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.smaller + + MaterialIcon { + id: icon + + text: categoryItem.icon + font.pointSize: 22 + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.preferredWidth: icon.contentWidth + Layout.fillHeight: true + verticalAlignment: Text.AlignVCenter + } + + CustomText { + id: text + + text: categoryItem.name + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: Appearance.spacing.normal + verticalAlignment: Text.AlignVCenter + } + } + + StateLayer { + id: layer + + onClicked: { + root.content.currentCategory = categoryItem.name.toLowerCase(); + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/Appearance.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/Appearance.qml new file mode 100644 index 0000000..558456a --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/Appearance.qml @@ -0,0 +1,68 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Modules.Settings.Controls +import qs.Config +import qs.Helpers + +CustomRect { + id: root + + ColumnLayout { + id: clayout + + anchors.left: parent.left + anchors.right: parent.right + + CustomRect { + + Layout.preferredHeight: colorLayout.implicitHeight + Layout.fillWidth: true + + color: DynamicColors.tPalette.m3surfaceContainer + + ColumnLayout { + id: colorLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large + + Settings { + name: "smth" + } + + SettingSwitch { + name: "wallust" + setting: Config.general.color.wallust + } + } + } + } + + component Settings: CustomRect { + id: settingsItem + + required property string name + + Layout.preferredWidth: 200 + Layout.preferredHeight: 42 + radius: 4 + + CustomText { + id: text + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.smaller + + text: settingsItem.name + font.pointSize: 32 + font.bold: true + verticalAlignment: Text.AlignVCenter + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/Background.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/Background.qml new file mode 100644 index 0000000..f905769 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/Background.qml @@ -0,0 +1,13 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +CustomRect { + id: root + +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/General.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/General.qml new file mode 100644 index 0000000..8594508 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Categories/General.qml @@ -0,0 +1,56 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +CustomRect { + id: root + + ColumnLayout { + id: clayout + + anchors.fill: parent + + Settings { + name: "apps" + } + + Item { + + } + } + + component Settings: CustomRect { + id: settingsItem + + required property string name + + implicitWidth: 200 + implicitHeight: 42 + radius: 4 + + RowLayout { + id: layout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.smaller + + CustomText { + id: text + + text: settingsItem.name + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: Appearance.spacing.normal + verticalAlignment: Text.AlignVCenter + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Content.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Content.qml new file mode 100644 index 0000000..4973b37 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Content.qml @@ -0,0 +1,101 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Controls +import qs.Components +import qs.Modules as Modules +import qs.Modules.Settings.Categories as Cat +import qs.Config +import qs.Helpers + +Item { + id: root + + required property PersistentProperties visibilities + readonly property real nonAnimWidth: view.implicitWidth + 500 + viewWrapper.anchors.margins * 2 + readonly property real nonAnimHeight: view.implicitHeight + viewWrapper.anchors.margins * 2 + property string currentCategory: "general" + + implicitWidth: nonAnimWidth + implicitHeight: nonAnimHeight + + Connections { + target: root + + function onCurrentCategoryChanged() { + stack.pop(); + if ( currentCategory === "general" ) { + stack.push(general); + } else if ( currentCategory === "wallpaper" ) { + stack.push(background); + } else if ( currentCategory === "appearance" ) { + stack.push(appearance); + } + } + } + + ClippingRectangle { + id: viewWrapper + anchors.fill: parent + anchors.margins: Appearance.padding.smaller + color: "transparent" + + Item { + id: view + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight + + Categories { + id: layout + + content: root + + anchors.fill: parent + } + } + + CustomClippingRect { + id: categoryContent + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: view.right + anchors.leftMargin: Appearance.spacing.smaller + + radius: 4 + + color: DynamicColors.tPalette.m3surfaceContainer + + StackView { + id: stack + + anchors.fill: parent + anchors.margins: Appearance.padding.smaller + + initialItem: general + } + } + } + + Component { + id: general + + Cat.General {} + } + + Component { + id: background + + Cat.Background {} + } + + Component { + id: appearance + + Cat.Appearance {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Controls/SettingSwitch.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Controls/SettingSwitch.qml new file mode 100644 index 0000000..5116be3 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Controls/SettingSwitch.qml @@ -0,0 +1,36 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +RowLayout { + id: root + + required property bool setting + required property string name + + Layout.preferredHeight: 42 + Layout.fillWidth: true + + CustomText { + id: text + + text: root.name + font.pointSize: 16 + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft + } + + CustomSwitch { + id: cswitch + + Layout.alignment: Qt.AlignRight + + checked: root.setting + onToggled: root.setting = checked + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Settings.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Settings.qml new file mode 100644 index 0000000..11ca396 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Settings.qml @@ -0,0 +1,12 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +Item { + +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Wrapper.qml new file mode 100644 index 0000000..b8555c2 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Settings/Wrapper.qml @@ -0,0 +1,65 @@ +import Quickshell +import QtQuick +import qs.Components +import qs.Config +import qs.Helpers + +Item { + id: root + + required property PersistentProperties visibilities + required property var panels + + implicitWidth: content.implicitWidth + implicitHeight: 0 + + visible: height > 0 + + states: State { + name: "visible" + + when: root.visibilities.settings + + PropertyChanges { + root.implicitHeight: content.implicitHeight + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitHeight" + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + }, + + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitHeight" + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + ] + + Loader { + id: content + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + visible: true + active: true + + sourceComponent: Content { + visibilities: root.visibilities + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Shortcuts.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Shortcuts.qml new file mode 100644 index 0000000..3217bd1 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Shortcuts.qml @@ -0,0 +1,53 @@ +import ZShell +import Quickshell +import Quickshell.Io +import qs.Components +import qs.Helpers + +Scope { + id: root + + property bool launcherInterrupted + readonly property bool hasFullscreen: Hypr.focusedWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen === 2) ?? false + + + CustomShortcut { + name: "toggle-launcher" + description: "Toggle launcher" + onPressed: root.launcherInterrupted = false + onReleased: { + if (!root.launcherInterrupted && !root.hasFullscreen) { + const visibilities = Visibilities.getForActive(); + visibilities.launcher = !visibilities.launcher; + } + root.launcherInterrupted = false; + } + } + + CustomShortcut { + name: "toggle-nc" + + onPressed: { + const visibilities = Visibilities.getForActive() + visibilities.sidebar = !visibilities.sidebar + } + } + + CustomShortcut { + name: "show-osd" + + onPressed: { + const visibilities = Visibilities.getForActive() + visibilities.osd = !visibilities.osd + } + } + + CustomShortcut { + name: "toggle-settings" + + onPressed: { + const visibilities = Visibilities.getForActive() + visibilities.settings = !visibilities.settings + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Time.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Time.qml new file mode 100644 index 0000000..230f413 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Time.qml @@ -0,0 +1,29 @@ +pragma Singleton + +import Quickshell +import QtQuick + +Singleton { + id: root + property alias enabled: clock.enabled + readonly property date date: clock.date + readonly property int hours: clock.hours + readonly property int minutes: clock.minutes + readonly property int seconds: clock.seconds + + readonly property string timeStr: format("hh:mm:ss") + readonly property string dateStr: format("ddd d MMM - hh:mm:ss") + readonly property list timeComponents: timeStr.split(":") + readonly property string hourStr: timeComponents[0] ?? "" + readonly property string minuteStr: timeComponents[1] ?? "" + readonly property string secondStr: timeComponents[2] ?? "" + + function format(fmt: string): string { + return Qt.formatDateTime(clock.date, fmt); + } + + SystemClock { + id: clock + precision: SystemClock.Seconds + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayItem.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayItem.qml new file mode 100644 index 0000000..ef6d531 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayItem.qml @@ -0,0 +1,66 @@ +import QtQuick.Layouts +import QtQuick +import Quickshell +import Quickshell.Services.SystemTray +import qs.Modules +import qs.Components +import qs.Config + +Item { + id: root + + required property SystemTrayItem item + required property PanelWindow bar + required property int ind + required property Wrapper popouts + required property RowLayout loader + property bool hasLoaded: false + + StateLayer { + anchors.fill: parent + anchors.margins: 3 + radius: 6 + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + if ( mouse.button === Qt.LeftButton ) { + root.item.activate(); + } else if ( mouse.button === Qt.RightButton ) { + root.popouts.currentName = `traymenu${ root.ind }`; + root.popouts.currentCenter = Qt.binding( () => root.mapToItem( root.loader, root.implicitWidth / 2, 0 ).x ); + root.popouts.hasCurrent = true; + if ( visibilities.sidebar || visibilities.dashboard ) { + visibilities.sidebar = false; + visibilities.dashboard = false; + } + } + } + } + + ColoredIcon { + id: icon + + anchors.centerIn: parent + source: root.item.icon + implicitSize: 22 + color: DynamicColors.palette.m3onSurface + layer.enabled: DynamicColors.light + } + + // Image { + // id: icon + // + // property bool batteryHDPI: root.bar.screen.x < 0 && root.item.icon.includes("battery") + // property bool nmHDPI: root.bar.screen.x < 0 && root.item.icon.includes("nm-") + // + // anchors.centerIn: parent + // width: batteryHDPI ? 26 : ( nmHDPI ? 25 : 22 ) + // height: batteryHDPI ? 26 : ( nmHDPI ? 25 : 22 ) + // source: root.item.icon + // mipmap: true + // smooth: ( batteryHDPI || nmHDPI ) ? false : true + // asynchronous: true + // sourceSize.width: ( batteryHDPI || nmHDPI ) ? 16 : 22 + // sourceSize.height: ( batteryHDPI || nmHDPI ) ? 16 : 22 + // fillMode: Image.PreserveAspectFit + // } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayMenu.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayMenu.qml new file mode 100644 index 0000000..2540a2d --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayMenu.qml @@ -0,0 +1,356 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell.Hyprland +import QtQml +import qs.Effects +import qs.Config + +PanelWindow { + id: root + + signal menuActionTriggered() + signal finishedLoading() + required property QsMenuHandle trayMenu + required property point trayItemRect + required property PanelWindow bar + property var menuStack: [] + property real scaleValue: 0 + property alias focusGrab: grab.active + property int entryHeight: 30 + property int biggestWidth: 0 + property int menuItemCount: menuOpener.children.values.length + + property color backgroundColor: DynamicColors.tPalette.m3surface + property color highlightColor: DynamicColors.tPalette.m3primaryContainer + property color textColor: DynamicColors.palette.m3onSurface + property color disabledHighlightColor: DynamicColors.layer(DynamicColors.palette.m3primaryContainer, 0) + property color disabledTextColor: DynamicColors.layer(DynamicColors.palette.m3onSurface, 0) + + QsMenuOpener { + id: menuOpener + menu: root.trayMenu + } + + // onTrayMenuChanged: { + // listLayout.forceLayout(); + // } + + visible: false + color: "transparent" + anchors { + top: true + left: true + right: true + bottom: true + } + + mask: Region { id: mask; item: menuRect } + + function goBack() { + if ( root.menuStack.length > 0 ) { + menuChangeAnimation.start(); + root.biggestWidth = 0; + root.trayMenu = root.menuStack.pop(); + listLayout.positionViewAtBeginning(); + backEntry.visible = false; + } + } + + function updateMask() { + root.mask.changed(); + } + + onVisibleChanged: { + if ( !visible ) + root.menuStack.pop(); + backEntry.visible = false; + + openAnim.start(); + } + + HyprlandFocusGrab { + id: grab + windows: [ root ] + active: false + onCleared: { + closeAnim.start(); + } + } + + SequentialAnimation { + id: menuChangeAnimation + ParallelAnimation { + NumberAnimation { + duration: MaterialEasing.standardTime / 2 + easing.bezierCurve: MaterialEasing.expressiveEffects + from: 0 + property: "x" + target: translateAnim + to: -listLayout.width / 2 + } + + NumberAnimation { + duration: MaterialEasing.standardTime / 2 + easing.bezierCurve: MaterialEasing.standard + from: 1 + property: "opacity" + target: columnLayout + to: 0 + } + } + + PropertyAction { + property: "menu" + target: columnLayout + } + + ParallelAnimation { + NumberAnimation { + duration: MaterialEasing.standardTime / 2 + easing.bezierCurve: MaterialEasing.standard + from: 0 + property: "opacity" + target: columnLayout + to: 1 + } + + NumberAnimation { + duration: MaterialEasing.standardTime / 2 + easing.bezierCurve: MaterialEasing.expressiveEffects + from: listLayout.width / 2 + property: "x" + target: translateAnim + to: 0 + } + } + } + + onMenuActionTriggered: { + if ( root.menuStack.length > 0 ) { + backEntry.visible = true; + } + } + + ParallelAnimation { + id: closeAnim + Anim { + target: menuRect + property: "implicitHeight" + to: 0 + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + Anim { + targets: [ menuRect, shadowRect ] + property: "opacity" + from: 1 + to: 0 + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + onFinished: { + root.visible = false; + } + } + + ParallelAnimation { + id: openAnim + Anim { + target: menuRect + property: "implicitHeight" + from: 0 + to: listLayout.contentHeight + ( root.menuStack.length > 0 ? root.entryHeight + 10 : 10 ) + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + Anim { + targets: [ menuRect, shadowRect ] + property: "opacity" + from: 0 + to: 1 + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + ShadowRect { + id: shadowRect + anchors.fill: menuRect + radius: menuRect.radius + } + + Rectangle { + id: menuRect + x: Math.round( root.trayItemRect.x - ( menuRect.implicitWidth / 2 ) + 11 ) + y: Math.round( root.trayItemRect.y - 5 ) + implicitWidth: listLayout.contentWidth + 10 + implicitHeight: listLayout.contentHeight + ( root.menuStack.length > 0 ? root.entryHeight + 10 : 10 ) + color: root.backgroundColor + radius: 8 + clip: true + + Behavior on implicitWidth { + NumberAnimation { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Behavior on implicitHeight { + NumberAnimation { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + ColumnLayout { + id: columnLayout + anchors.fill: parent + anchors.margins: 5 + spacing: 0 + transform: [ + Translate { + id: translateAnim + x: 0 + y: 0 + } + ] + ListView { + id: listLayout + Layout.fillWidth: true + Layout.preferredHeight: contentHeight + spacing: 0 + contentWidth: root.biggestWidth + contentHeight: contentItem.childrenRect.height + model: menuOpener.children + + delegate: Rectangle { + id: menuItem + required property int index + required property QsMenuEntry modelData + property var child: QsMenuOpener { + menu: menuItem.modelData + } + property bool containsMouseAndEnabled: mouseArea.containsMouse && menuItem.modelData.enabled + property bool containsMouseAndNotEnabled: mouseArea.containsMouse && !menuItem.modelData.enabled + width: widthMetrics.width + (menuItem.modelData.icon ?? "" ? 30 : 0) + (menuItem.modelData.hasChildren ? 30 : 0) + 20 + anchors.left: parent.left + anchors.right: parent.right + height: menuItem.modelData.isSeparator ? 1 : root.entryHeight + color: menuItem.modelData.isSeparator ? "#20FFFFFF" : containsMouseAndEnabled ? root.highlightColor : containsMouseAndNotEnabled ? root.disabledHighlightColor : "transparent" + radius: 4 + visible: true + + Behavior on color { + CAnim { + duration: 150 + } + } + + Component.onCompleted: { + var biggestWidth = root.biggestWidth; + var currentWidth = widthMetrics.width + (menuItem.modelData.icon ?? "" ? 30 : 0) + (menuItem.modelData.hasChildren ? 30 : 0) + 20; + if ( currentWidth > biggestWidth ) { + root.biggestWidth = currentWidth; + } + } + + TextMetrics { + id: widthMetrics + text: menuItem.modelData.text + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + preventStealing: true + propagateComposedEvents: true + acceptedButtons: Qt.LeftButton + onClicked: { + if ( !menuItem.modelData.hasChildren ) { + if ( menuItem.modelData.enabled ) { + menuItem.modelData.triggered(); + closeAnim.start(); + } + } else { + root.menuStack.push(root.trayMenu); + menuChangeAnimation.start(); + root.biggestWidth = 0; + root.trayMenu = menuItem.modelData; + listLayout.positionViewAtBeginning(); + root.menuActionTriggered(); + } + } + } + + RowLayout { + anchors.fill: parent + Text { + id: menuText + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + Layout.leftMargin: 10 + text: menuItem.modelData.text + color: menuItem.modelData.enabled ? root.textColor : root.disabledTextColor + } + Image { + id: iconImage + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.rightMargin: 10 + Layout.maximumWidth: 20 + Layout.maximumHeight: 20 + source: menuItem.modelData.icon + sourceSize.width: width + sourceSize.height: height + fillMode: Image.PreserveAspectFit + layer.enabled: true + layer.effect: ColorOverlay { + color: menuItem.modelData.enabled ? "white" : "gray" + } + } + Text { + id: textArrow + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.rightMargin: 10 + Layout.bottomMargin: 5 + Layout.maximumWidth: 20 + Layout.maximumHeight: 20 + text: "" + color: menuItem.modelData.enabled ? "white" : "gray" + visible: menuItem.modelData.hasChildren ?? false + } + } + } + } + Rectangle { + id: backEntry + visible: false + Layout.fillWidth: true + Layout.preferredHeight: root.entryHeight + color: mouseAreaBack.containsMouse ? "#15FFFFFF" : "transparent" + radius: 4 + + MouseArea { + id: mouseAreaBack + anchors.fill: parent + hoverEnabled: true + onClicked: { + root.goBack(); + } + } + + Text { + anchors.fill: parent + anchors.leftMargin: 10 + verticalAlignment: Text.AlignVCenter + text: "Back " + color: "white" + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayMenuPopout.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayMenuPopout.qml new file mode 100644 index 0000000..cb0cd24 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayMenuPopout.qml @@ -0,0 +1,247 @@ +pragma ComponentBehavior: Bound + +import qs.Components +import qs.Config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Controls +import QtQuick.Effects + +StackView { + id: root + + required property Item popouts + required property QsMenuHandle trayItem + + property int rootWidth: 0 + property int biggestWidth: 0 + + implicitWidth: currentItem.implicitWidth + implicitHeight: currentItem.implicitHeight + + initialItem: SubMenu { + handle: root.trayItem + } + + pushEnter: NoAnim {} + pushExit: NoAnim {} + popEnter: NoAnim {} + popExit: NoAnim {} + + component NoAnim: Transition { + NumberAnimation { + duration: 0 + } + } + + component SubMenu: Column { + id: menu + + required property QsMenuHandle handle + property bool isSubMenu + property bool shown + + padding: 0 + spacing: 4 + + opacity: shown ? 1 : 0 + scale: shown ? 1 : 0.8 + + Component.onCompleted: shown = true + StackView.onActivating: shown = true + StackView.onDeactivating: shown = false + StackView.onRemoved: destroy() + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + QsMenuOpener { + id: menuOpener + + menu: menu.handle + } + + Repeater { + model: menuOpener.children + + CustomRect { + id: item + + required property QsMenuEntry modelData + + implicitWidth: root.biggestWidth + implicitHeight: modelData.isSeparator ? 1 : children.implicitHeight + + radius: 4 + color: modelData.isSeparator ? DynamicColors.palette.m3outlineVariant : "transparent" + + Loader { + id: children + + anchors.left: parent.left + anchors.right: parent.right + + active: !item.modelData.isSeparator + asynchronous: true + + sourceComponent: Item { + implicitHeight: 30 + + StateLayer { + radius: item.radius + disabled: !item.modelData.enabled + + function onClicked(): void { + const entry = item.modelData; + if (entry.hasChildren) { + root.rootWidth = root.biggestWidth; + root.biggestWidth = 0; + root.push(subMenuComp.createObject(null, { + handle: entry, + isSubMenu: true + })); + } else { + item.modelData.triggered(); + root.popouts.hasCurrent = false; + } + } + } + + Loader { + id: icon + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 10 + + active: item.modelData.icon !== "" + asynchronous: true + + sourceComponent: Item { + implicitHeight: label.implicitHeight + implicitWidth: label.implicitHeight + IconImage { + id: iconImage + implicitSize: parent.implicitHeight + source: item.modelData.icon + visible: false + } + + MultiEffect { + anchors.fill: iconImage + source: iconImage + colorization: 1.0 + colorizationColor: item.modelData.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline + } + } + } + + CustomText { + id: label + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 10 + + text: labelMetrics.elidedText + color: item.modelData.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline + } + + TextMetrics { + id: labelMetrics + + text: item.modelData.text + font.pointSize: label.font.pointSize + font.family: label.font.family + + Component.onCompleted: { + var biggestWidth = root.biggestWidth; + var currentWidth = labelMetrics.width + (item.modelData.icon ?? "" ? 30 : 0) + (item.modelData.hasChildren ? 30 : 0) + 20; + if ( currentWidth > biggestWidth ) { + root.biggestWidth = currentWidth; + } + } + } + + Loader { + id: expand + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + + active: item.modelData.hasChildren + asynchronous: true + + sourceComponent: MaterialIcon { + text: "chevron_right" + color: item.modelData.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline + } + } + } + } + } + } + + Loader { + active: menu.isSubMenu + asynchronous: true + + sourceComponent: Item { + implicitWidth: back.implicitWidth + implicitHeight: back.implicitHeight + 2 / 2 + + Item { + anchors.bottom: parent.bottom + implicitWidth: back.implicitWidth + 10 + implicitHeight: back.implicitHeight + + CustomRect { + anchors.fill: parent + radius: 4 + color: DynamicColors.palette.m3secondaryContainer + + StateLayer { + radius: parent.radius + color: DynamicColors.palette.m3onSecondaryContainer + + function onClicked(): void { + root.pop(); + root.biggestWidth = root.rootWidth; + } + } + } + + Row { + id: back + + anchors.verticalCenter: parent.verticalCenter + + MaterialIcon { + anchors.verticalCenter: parent.verticalCenter + text: "chevron_left" + color: DynamicColors.palette.m3onSecondaryContainer + } + + CustomText { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Back") + color: DynamicColors.palette.m3onSecondaryContainer + } + } + } + } + } + } + + Component { + id: subMenuComp + + SubMenu {} + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayWidget.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayWidget.qml new file mode 100644 index 0000000..4648b80 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/TrayWidget.qml @@ -0,0 +1,37 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Services.SystemTray + +Row { + id: root + + anchors.top: parent.top + anchors.bottom: parent.bottom + + required property PanelWindow bar + required property Wrapper popouts + required property RowLayout loader + readonly property alias items: repeater + + spacing: 0 + + Repeater { + id: repeater + model: SystemTray.items + TrayItem { + id: trayItem + required property SystemTrayItem modelData + required property int index + ind: index + popouts: root.popouts + loader: root.loader + implicitHeight: 34 + implicitWidth: 34 + item: modelData + bar: root.bar + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UPower/UPowerPopout.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UPower/UPowerPopout.qml new file mode 100644 index 0000000..ea1aa92 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UPower/UPowerPopout.qml @@ -0,0 +1,183 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell.Services.UPower +import qs.Config +import qs.Components +import qs.Modules + +Item { + id: root + + required property var wrapper + + implicitWidth: profiles.implicitWidth + implicitHeight: profiles.implicitHeight + + CustomRect { + id: profiles + + property string current: { + const p = PowerProfiles.profile; + if (p === PowerProfile.PowerSaver) + return saver.icon; + if (p === PowerProfile.Performance) + return perf.icon; + return balance.icon; + } + + anchors.horizontalCenter: parent.horizontalCenter + + implicitWidth: saver.implicitHeight + balance.implicitHeight + perf.implicitHeight + 8 * 2 + saverLabel.contentWidth + implicitHeight: Math.max(saver.implicitHeight, balance.implicitHeight, perf.implicitHeight) + 5 * 2 + saverLabel.contentHeight + + color: DynamicColors.tPalette.m3surfaceContainer + // color: "transparent" + radius: 6 + + CustomRect { + id: indicator + + color: DynamicColors.palette.m3primary + radius: 1000 + state: profiles.current + + states: [ + State { + name: saver.icon + + Fill { + item: saver + } + }, + State { + name: balance.icon + + Fill { + item: balance + } + }, + State { + name: perf.icon + + Fill { + item: perf + } + } + ] + + transitions: Transition { + AnchorAnimation { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + easing.type: Easing.BezierSpline + } + } + } + + Profile { + id: saver + + anchors.top: parent.top + anchors.topMargin: 8 + anchors.left: parent.left + anchors.leftMargin: 25 + + text: "Power Saver" + profile: PowerProfile.PowerSaver + icon: "nest_eco_leaf" + } + + CustomText { + id: saverLabel + anchors.top: saver.bottom + anchors.horizontalCenter: saver.horizontalCenter + font.bold: true + text: saver.text + } + + Profile { + id: balance + + anchors.top: parent.top + anchors.topMargin: 8 + anchors.horizontalCenter: parent.horizontalCenter + + text: "Balanced" + profile: PowerProfile.Balanced + icon: "power_settings_new" + } + + CustomText { + id: balanceLabel + anchors.top: balance.bottom + anchors.horizontalCenter: balance.horizontalCenter + font.bold: true + text: balance.text + } + + Profile { + id: perf + + anchors.top: parent.top + anchors.topMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 25 + + text: "Performance" + profile: PowerProfile.Performance + icon: "bolt" + } + + CustomText { + id: perfLabel + anchors.top: perf.bottom + anchors.horizontalCenter: perf.horizontalCenter + font.bold: true + text: perf.text + } + } + + component Fill: AnchorChanges { + required property Item item + + target: indicator + anchors.left: item.left + anchors.right: item.right + anchors.top: item.top + anchors.bottom: item.bottom + } + + component Profile: Item { + required property string icon + required property int profile + required property string text + + implicitWidth: icon.implicitHeight + 5 * 2 + implicitHeight: icon.implicitHeight + 5 * 2 + + StateLayer { + radius: 1000 + color: profiles.current === parent.icon ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface + + function onClicked(): void { + PowerProfiles.profile = parent.profile; + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + + text: parent.icon + font.pointSize: 36 + color: profiles.current === text ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface + fill: profiles.current === text ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UPower/UPowerWidget.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UPower/UPowerWidget.qml new file mode 100644 index 0000000..a0dfcfe --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UPower/UPowerWidget.qml @@ -0,0 +1,57 @@ +import Quickshell.Services.UPower +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config +import qs.Helpers as Helpers + +Item { + id: root + + implicitWidth: layout.childrenRect.width + 10 * 2 + anchors.top: parent.top + anchors.bottom: parent.bottom + + CustomRect { + anchors.fill: parent + anchors.topMargin: 4 + anchors.bottomMargin: 4 + color: DynamicColors.tPalette.m3surfaceContainer + radius: 1000 + } + + RowLayout { + id: layout + anchors.centerIn: parent + + MaterialIcon { + animate: true + Layout.alignment: Qt.AlignVCenter + text: { + if (!Helpers.UPower.displayDevice.isLaptopBattery) { + if (PowerProfiles.profile === PowerProfile.PowerSaver) + return "nest_eco_leaf"; + if (PowerProfiles.profile === PowerProfile.Performance) + return "bolt"; + return "power_settings_new"; + } + + const perc = Helpers.UPower.displayDevice.percentage; + const charging = [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(Helpers.UPower.displayDevice.state); + if (perc === 1) + return charging ? "battery_charging_full" : "battery_full"; + let level = Math.floor(perc * 7); + if (charging && (level === 4 || level === 1)) + level--; + return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`; + } + color: !Helpers.UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3error + fill: 1 + } + + CustomText { + Layout.alignment: Qt.AlignVCenter + text: Helpers.UPower.displayDevice.isLaptopBattery ? qsTr("%1%").arg(Math.round(UPower.displayDevice.percentage * 100)) : (PowerProfiles.profile === PowerProfile.PowerSaver ? qsTr("Pwr Sav") : PowerProfiles.profile === PowerProfile.Performance ? qsTr("Perf") : qsTr("Bal")) + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Updates.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Updates.qml new file mode 100644 index 0000000..89a67b7 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Updates.qml @@ -0,0 +1,35 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import Quickshell.Io +import qs.Modules + +Singleton { + property int availableUpdates: 0 + + Timer { + interval: 1 + running: true + repeat: true + onTriggered: { + updatesProc.running = true + interval = 5000 + } + } + + Process { + id: updatesProc + running: false + + command: ["checkupdates"] + stdout: StdioCollector { + onStreamFinished: { + const output = this.text + const lines = output.trim().split("\n").filter(line => line.length > 0) + availableUpdates = lines.length + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UpdatesWidget.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UpdatesWidget.qml new file mode 100644 index 0000000..0431f71 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/UpdatesWidget.qml @@ -0,0 +1,62 @@ +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules +import qs.Config + +Item { + id: root + property int countUpdates: Updates.availableUpdates + implicitWidth: textMetrics.width + contentRow.spacing + 30 + anchors.top: parent.top + anchors.bottom: parent.bottom + property color textColor: DynamicColors.palette.m3onSurface + + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + implicitHeight: 22 + radius: height / 2 + color: DynamicColors.tPalette.m3surfaceContainer + Behavior on color { + CAnim {} + } + } + + RowLayout { + id: contentRow + spacing: 10 + anchors { + fill: parent + leftMargin: 5 + rightMargin: 5 + } + + Text { + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + font.family: "Material Symbols Rounded" + font.pixelSize: 18 + text: "\uf569" + color: root.textColor + Behavior on color { + CAnim {} + } + } + + TextMetrics { + id: textMetrics + font.pixelSize: 16 + text: root.countUpdates + } + + Text { + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + text: textMetrics.text + color: root.textColor + Behavior on color { + CAnim {} + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/WSOverview/OverviewPopout.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/WSOverview/OverviewPopout.qml new file mode 100644 index 0000000..7ce7349 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/WSOverview/OverviewPopout.qml @@ -0,0 +1,84 @@ +import Quickshell +import Quickshell.Hyprland +import Quickshell.Wayland +import QtQuick +import QtQuick.Layouts +import qs.Config +import qs.Components +import qs.Modules +import qs.Helpers + +Item { + id: root + + required property Item wrapper + required property ShellScreen screen + + implicitWidth: layout.implicitWidth + 16 + implicitHeight: layout.implicitHeight + 16 + + GridLayout { + id: layout + anchors.centerIn: parent + + columnSpacing: 8 + rowSpacing: 8 + + Repeater { + model: Hypr.workspaces + + CustomRect { + id: workspacePreview + required property HyprlandWorkspace modelData + + border.color: "white" + border.width: 1 + radius: 8 + Layout.preferredWidth: 320 + 10 + Layout.preferredHeight: 180 + 10 + + Repeater { + model: workspacePreview.modelData.toplevels + + Item { + id: preview + anchors.fill: parent + anchors.margins: 5 + + required property HyprlandToplevel modelData + property rect appPosition: { + let { + at: [cx, cy], + size: [cw, ch] + } = modelData.lastIpcObject; + + cx -= modelData.monitor.x; + cy -= modelData.monitor.y; + + return Qt.rect( (cx / 8), (cy / 8), (cw / 8), (ch / 8) ) + } + + CustomRect { + border.color: DynamicColors.tPalette.m3outline + border.width: 1 + radius: 4 + implicitWidth: preview.appPosition.width + implicitHeight: preview.appPosition.height + + x: preview.appPosition.x + y: preview.appPosition.y - 3.4 + + ScreencopyView { + id: previewCopy + anchors.fill: parent + + captureSource: preview.modelData.wayland + live: true + } + } + } + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wallpaper/WallBackground.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wallpaper/WallBackground.qml new file mode 100644 index 0000000..a5b080a --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wallpaper/WallBackground.qml @@ -0,0 +1,80 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import qs.Components +import qs.Helpers +import qs.Config + +Item { + id: root + + property string source: Wallpapers.current + property Image current: one + + anchors.fill: parent + + onSourceChanged: { + if (!source) { + current = null; + } else if (current === one) { + two.update(); + } else { + one.update(); + } + } + + Component.onCompleted: { + console.log(root.source) + if (source) + Qt.callLater(() => one.update()); + } + + Img { + id: one + } + + Img { + id: two + } + + component Img: CachingImage { + id: img + + function update(): void { + if (path === root.source) { + root.current = this; + } else { + path = root.source; + } + } + + anchors.fill: parent + + opacity: 0 + scale: Wallpapers.showPreview ? 1 : 0.8 + asynchronous: true + onStatusChanged: { + if (status === Image.Ready) { + root.current = this; + } + } + + states: State { + name: "visible" + when: root.current === img + + PropertyChanges { + img.opacity: 1 + img.scale: 1 + } + } + + transitions: Transition { + Anim { + target: img + properties: "opacity,scale" + duration: Config.background.wallFadeDuration + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wallpaper/Wallpaper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wallpaper/Wallpaper.qml new file mode 100644 index 0000000..76fdf64 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wallpaper/Wallpaper.qml @@ -0,0 +1,31 @@ +import Quickshell +import QtQuick +import Quickshell.Wayland +import qs.Config + +Loader { + + asynchronous: true + active: Config.background.enabled + + sourceComponent: Variants { + model: Quickshell.screens + PanelWindow { + id: root + required property var modelData + screen: modelData + WlrLayershell.namespace: "ZShell-Wallpaper" + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Bottom + color: "transparent" + + anchors { + top: true + left: true + right: true + bottom: true + } + WallBackground {} + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/WindowTitle.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/WindowTitle.qml new file mode 100644 index 0000000..ae30bda --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/WindowTitle.qml @@ -0,0 +1,85 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import qs.Components +import qs.Config +import qs.Helpers + +Item { + id: root + + required property var bar + required property Brightness.Monitor monitor + property color colour: DynamicColors.palette.m3primary + + readonly property int maxHeight: { + const otherModules = bar.children.filter(c => c.id && c.item !== this && c.id !== "spacer"); + const otherHeight = otherModules.reduce((acc, curr) => acc + (curr.item.nonAnimHeight ?? curr.height), 0); + // Length - 2 cause repeater counts as a child + return bar.height - otherHeight - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2; + } + property Title current: text1 + + clip: true + implicitWidth: current.implicitWidth + current.anchors.leftMargin + implicitHeight: current.implicitHeight + + // MaterialIcon { + // id: icon + // + // anchors.verticalCenter: parent.verticalCenter + // + // animate: true + // text: Icons.getAppCategoryIcon(Hypr.activeToplevel?.lastIpcObject.class, "desktop_windows") + // color: root.colour + // } + + Title { + id: text1 + } + + Title { + id: text2 + } + + TextMetrics { + id: metrics + + text: Hypr.activeToplevel?.title ?? qsTr("Desktop") + font.pointSize: 12 + font.family: "Rubik" + + onTextChanged: { + const next = root.current === text1 ? text2 : text1; + next.text = elidedText; + root.current = next; + } + onElideWidthChanged: root.current.text = elidedText + } + + Behavior on implicitWidth { + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + component Title: CustomText { + id: text + + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 7 + + font.pointSize: metrics.font.pointSize + font.family: metrics.font.family + color: root.colour + opacity: root.current === this ? 1 : 0 + + width: implicitWidth + height: implicitHeight + + Behavior on opacity { + Anim {} + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Workspaces.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Workspaces.qml new file mode 100644 index 0000000..1d1c084 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Workspaces.qml @@ -0,0 +1,128 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Effects +import Quickshell +import Quickshell.Hyprland +import qs.Config +import qs.Components + +Item { + id: itemRoot + required property PanelWindow bar + anchors.top: parent.top + anchors.bottom: parent.bottom + implicitWidth: workspacesRow.implicitWidth + 10 + + Behavior on implicitWidth { + NumberAnimation { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } + + Rectangle { + id: root + + property HyprlandMonitor monitor: Hyprland.monitorFor( itemRoot.bar?.screen ) + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + implicitHeight: 22 + + function shouldShow(monitor) { + Hyprland.refreshWorkspaces(); + Hyprland.refreshMonitors(); + if ( monitor === root.monitor ) { + return true; + } else { + return false; + } + } + + color: DynamicColors.tPalette.m3surfaceContainer + radius: height / 2 + + Behavior on color { + CAnim {} + } + + RowLayout { + id: workspacesRow + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 6 + spacing: 8 + + Repeater { + model: Hyprland.workspaces + + RowLayout { + id: workspaceIndicator + required property var modelData + visible: root.shouldShow( workspaceIndicator.modelData.monitor ) + CustomText { + text: workspaceIndicator.modelData.name + font.pointSize: 12 + color: workspaceIndicator.modelData.id === Hyprland.focusedWorkspace.id ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant + visible: true + } + + Rectangle { + + implicitWidth: 14 + implicitHeight: 14 + radius: height / 2 + border.width: 1 + + color: "transparent" + border.color: workspaceIndicator.modelData.id === Hyprland.focusedWorkspace.id ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant + + + scale: 1.0 + opacity: 1.0 + + CustomRect { + anchors.centerIn: parent + implicitWidth: 8 + implicitHeight: 8 + + radius: implicitHeight / 2 + color: workspaceIndicator.modelData.id === Hyprland.focusedWorkspace.id ? DynamicColors.palette.m3primary : "transparent" + } + + Behavior on border.color { + ColorAnimation { + duration: 150 + easing.type: Easing.InOutQuad + } + } + + NumberAnimation on scale { + from: 0.0 + to: 1.0 + duration: 300 + easing.type: Easing.OutBack + } + + NumberAnimation on opacity { + from: 0.0 + to: 1.0 + duration: 200 + } + + MouseArea { + anchors.fill: parent + onClicked: { + workspaceIndicator.modelData.activate(); + } + } + } + } + } + } + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wrapper.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wrapper.qml new file mode 100644 index 0000000..6c395ce --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Modules/Wrapper.qml @@ -0,0 +1,187 @@ +import Quickshell +import Quickshell.Wayland +import Quickshell.Hyprland +import QtQuick +import qs.Components +import qs.Config + +Item { + id: root + + required property ShellScreen screen + + readonly property real nonAnimWidth: children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth + readonly property real nonAnimHeight: hasCurrent ? children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight : 0 + readonly property Item current: content.item?.current ?? null + + property string currentName + property real currentCenter + property bool hasCurrent + + property string detachedMode + property string queuedMode + readonly property bool isDetached: detachedMode.length > 0 + + property int animLength: MaterialEasing.emphasizedDecelTime + property list animCurve: MaterialEasing.emphasized + + function detach(mode: string): void { + animLength = 600; + if (mode === "winfo") { + detachedMode = mode; + } else { + detachedMode = "any"; + queuedMode = mode; + } + focus = true; + } + + function close(): void { + hasCurrent = false; + animCurve = MaterialEasing.emphasizedDecel; + animLength = MaterialEasing.emphasizedDecelTime; + detachedMode = ""; + animCurve = MaterialEasing.emphasized; + } + + visible: width > 0 && height > 0 + clip: true + + implicitWidth: nonAnimWidth + implicitHeight: nonAnimHeight + + Keys.onEscapePressed: close() + + HyprlandFocusGrab { + active: root.isDetached + windows: [QsWindow.window] + onCleared: root.close() + } + + Binding { + when: root.isDetached + + target: QsWindow.window + property: "WlrLayershell.keyboardFocus" + value: WlrKeyboardFocus.OnDemand + } + + Comp { + id: content + + shouldBeActive: root.hasCurrent + asynchronous: true + + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + + sourceComponent: Content { + wrapper: root + } + } + + // Comp { + // shouldBeActive: root.detachedMode === "winfo" + // asynchronous: true + // anchors.centerIn: parent + // + // sourceComponent: WindowInfo { + // screen: root.screen + // client: Hypr.activeToplevel + // } + // } + + // Comp { + // shouldBeActive: root.detachedMode === "any" + // asynchronous: true + // anchors.centerIn: parent + // + // sourceComponent: ControlCenter { + // screen: root.screen + // active: root.queuedMode + // + // function close(): void { + // root.close(); + // } + // } + // } + + Behavior on x { + enabled: root.implicitHeight > 0 + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + Behavior on y { + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + Behavior on implicitWidth { + enabled: root.implicitHeight > 0 + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + Behavior on implicitHeight { + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + component Comp: Loader { + id: comp + + property bool shouldBeActive + + asynchronous: true + active: false + opacity: 0 + + states: State { + name: "active" + when: comp.shouldBeActive + + PropertyChanges { + comp.opacity: 1 + comp.active: true + } + } + + transitions: [ + Transition { + from: "" + to: "active" + + SequentialAnimation { + PropertyAction { + property: "active" + } + Anim { + property: "opacity" + } + } + }, + Transition { + from: "active" + to: "" + + SequentialAnimation { + Anim { + property: "opacity" + } + PropertyAction { + property: "active" + } + } + } + ] + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/Paths/Paths.qml b/pkg/zshell/etc/xdg/quickshell/zshell/Paths/Paths.qml new file mode 100644 index 0000000..373c7f6 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/Paths/Paths.qml @@ -0,0 +1,37 @@ +pragma Singleton + +import ZShell +import Quickshell +import qs.Config + +Singleton { + id: root + + readonly property string home: Quickshell.env("HOME") + readonly property string pictures: Quickshell.env("XDG_PICTURES_DIR") || `${home}/Pictures` + readonly property string videos: Quickshell.env("XDG_VIDEOS_DIR") || `${home}/Videos` + + readonly property string data: `${Quickshell.env("XDG_DATA_HOME") || `${home}/.local/share`}/zshell` + readonly property string state: `${Quickshell.env("XDG_STATE_HOME") || `${home}/.local/state`}/zshell` + readonly property string cache: `${Quickshell.env("XDG_CACHE_HOME") || `${home}/.cache`}/zshell` + readonly property string config: `${Quickshell.env("XDG_CONFIG_HOME") || `${home}/.config`}/zshell` + + readonly property string imagecache: `${cache}/imagecache` + readonly property string notifimagecache: `${imagecache}/notifs` + readonly property string wallsdir: Quickshell.env("ZSHELL_WALLPAPERS_DIR") || absolutePath(Config.wallpaperPath) + readonly property string recsdir: Quickshell.env("ZSHELL_RECORDINGS_DIR") || `${videos}/Recordings` + readonly property string libdir: Quickshell.env("ZSHELL_LIB_DIR") || "/usr/lib/zshell" + + function toLocalFile(path: url): string { + path = Qt.resolvedUrl(path); + return path.toString() ? ZShellIo.toLocalFile(path) : ""; + } + + function absolutePath(path: string): string { + return toLocalFile(path.replace("~", home)); + } + + function shortenHome(path: string): string { + return path.replace(home, "~"); + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/assets/pam.d/passwd b/pkg/zshell/etc/xdg/quickshell/zshell/assets/pam.d/passwd new file mode 100644 index 0000000..4b14064 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/assets/pam.d/passwd @@ -0,0 +1,6 @@ +#%PAM-1.0 + +auth required pam_faillock.so preauth +auth [success=1 default=bad] pam_unix.so nullok +auth [default=die] pam_faillock.so authfail +auth required pam_faillock.so authsucc diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/blurshader.glsl b/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/blurshader.glsl new file mode 100644 index 0000000..f59d20c --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/blurshader.glsl @@ -0,0 +1,22 @@ +uniform sampler2D image; + +out vec4 FragmentColor; + +uniform float offset[3] = float[](0.0, 1.3846153846, 3.2307692308); +uniform float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703); + +void main(void) { + + FragmentColor = texture2D(image, vec2(gl_FragCoord) / 1024.0) * weight[0]; + + for (int i=1; i<3; i++) { + + FragmentColor += + texture2D(image, (vec2(gl_FragCoord) + vec2(0.0, offset[i])) / 1024.0) + * weight[i]; + + FragmentColor += + texture2D(image, (vec2(gl_FragCoord) - vec2(0.0, offset[i])) / 1024.0) + * weight[i]; + } +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/opacitymask.frag b/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/opacitymask.frag new file mode 100644 index 0000000..7d93b06 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/opacitymask.frag @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + // qt_Matrix and qt_Opacity must always be both present + // if the built-in vertex shader is used. + mat4 qt_Matrix; + float qt_Opacity; +}; + +layout(binding = 1) uniform sampler2D source; +layout(binding = 2) uniform sampler2D maskSource; + +void main() { + fragColor = texture(source, qt_TexCoord0.st) * + (texture(maskSource, qt_TexCoord0.st).a) * qt_Opacity; +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/opacitymask.frag.qsb b/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/opacitymask.frag.qsb new file mode 100644 index 0000000..4aedc35 Binary files /dev/null and b/pkg/zshell/etc/xdg/quickshell/zshell/assets/shaders/opacitymask.frag.qsb differ diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/scripts/fuzzysort.js b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/fuzzysort.js new file mode 100644 index 0000000..94308ff --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/fuzzysort.js @@ -0,0 +1,705 @@ +.pragma library + +/* +https://github.com/farzher/fuzzysort + +MIT License + +Copyright (c) 2018 Stephen Kamenar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +var single = (search, target) => { + if(!search || !target) return NULL + + var preparedSearch = getPreparedSearch(search) + if(!isPrepared(target)) target = getPrepared(target) + + var searchBitflags = preparedSearch.bitflags + if((searchBitflags & target._bitflags) !== searchBitflags) return NULL + + return algorithm(preparedSearch, target) +} + +var go = (search, targets, options) => { + if(!search) return options?.all ? all(targets, options) : noResults + + var preparedSearch = getPreparedSearch(search) + var searchBitflags = preparedSearch.bitflags + var containsSpace = preparedSearch.containsSpace + + var threshold = denormalizeScore( options?.threshold || 0 ) + var limit = options?.limit || INFINITY + + var resultsLen = 0; var limitedCount = 0 + var targetsLen = targets.length + + function push_result(result) { + if(resultsLen < limit) { q.add(result); ++resultsLen } + else { + ++limitedCount + if(result._score > q.peek()._score) q.replaceTop(result) + } + } + + // This code is copy/pasted 3 times for performance reasons [options.key, options.keys, no keys] + + // options.key + if(options?.key) { + var key = options.key + for(var i = 0; i < targetsLen; ++i) { var obj = targets[i] + var target = getValue(obj, key) + if(!target) continue + if(!isPrepared(target)) target = getPrepared(target) + + if((searchBitflags & target._bitflags) !== searchBitflags) continue + var result = algorithm(preparedSearch, target) + if(result === NULL) continue + if(result._score < threshold) continue + + result.obj = obj + push_result(result) + } + + // options.keys + } else if(options?.keys) { + var keys = options.keys + var keysLen = keys.length + + outer: for(var i = 0; i < targetsLen; ++i) { var obj = targets[i] + + { // early out based on bitflags + var keysBitflags = 0 + for (var keyI = 0; keyI < keysLen; ++keyI) { + var key = keys[keyI] + var target = getValue(obj, key) + if(!target) { tmpTargets[keyI] = noTarget; continue } + if(!isPrepared(target)) target = getPrepared(target) + tmpTargets[keyI] = target + + keysBitflags |= target._bitflags + } + + if((searchBitflags & keysBitflags) !== searchBitflags) continue + } + + if(containsSpace) for(let i=0; i -1000) { + if(keysSpacesBestScores[i] > NEGATIVE_INFINITY) { + var tmp = (keysSpacesBestScores[i] + allowPartialMatchScores[i]) / 4/*bonus score for having multiple matches*/ + if(tmp > keysSpacesBestScores[i]) keysSpacesBestScores[i] = tmp + } + } + if(allowPartialMatchScores[i] > keysSpacesBestScores[i]) keysSpacesBestScores[i] = allowPartialMatchScores[i] + } + } + + if(containsSpace) { + for(let i=0; i -1000) { + if(score > NEGATIVE_INFINITY) { + var tmp = (score + result._score) / 4/*bonus score for having multiple matches*/ + if(tmp > score) score = tmp + } + } + if(result._score > score) score = result._score + } + } + + objResults.obj = obj + objResults._score = score + if(options?.scoreFn) { + score = options.scoreFn(objResults) + if(!score) continue + score = denormalizeScore(score) + objResults._score = score + } + + if(score < threshold) continue + push_result(objResults) + } + + // no keys + } else { + for(var i = 0; i < targetsLen; ++i) { var target = targets[i] + if(!target) continue + if(!isPrepared(target)) target = getPrepared(target) + + if((searchBitflags & target._bitflags) !== searchBitflags) continue + var result = algorithm(preparedSearch, target) + if(result === NULL) continue + if(result._score < threshold) continue + + push_result(result) + } + } + + if(resultsLen === 0) return noResults + var results = new Array(resultsLen) + for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll() + results.total = resultsLen + limitedCount + return results +} + + +// this is written as 1 function instead of 2 for minification. perf seems fine ... +// except when minified. the perf is very slow +var highlight = (result, open='', close='') => { + var callback = typeof open === 'function' ? open : undefined + + var target = result.target + var targetLen = target.length + var indexes = result.indexes + var highlighted = '' + var matchI = 0 + var indexesI = 0 + var opened = false + var parts = [] + + for(var i = 0; i < targetLen; ++i) { var char = target[i] + if(indexes[indexesI] === i) { + ++indexesI + if(!opened) { opened = true + if(callback) { + parts.push(highlighted); highlighted = '' + } else { + highlighted += open + } + } + + if(indexesI === indexes.length) { + if(callback) { + highlighted += char + parts.push(callback(highlighted, matchI++)); highlighted = '' + parts.push(target.substr(i+1)) + } else { + highlighted += char + close + target.substr(i+1) + } + break + } + } else { + if(opened) { opened = false + if(callback) { + parts.push(callback(highlighted, matchI++)); highlighted = '' + } else { + highlighted += close + } + } + } + highlighted += char + } + + return callback ? parts : highlighted +} + + +var prepare = (target) => { + if(typeof target === 'number') target = ''+target + else if(typeof target !== 'string') target = '' + var info = prepareLowerInfo(target) + return new_result(target, {_targetLower:info._lower, _targetLowerCodes:info.lowerCodes, _bitflags:info.bitflags}) +} + +var cleanup = () => { preparedCache.clear(); preparedSearchCache.clear() } + + +// Below this point is only internal code +// Below this point is only internal code +// Below this point is only internal code +// Below this point is only internal code + + +class Result { + get ['indexes']() { return this._indexes.slice(0, this._indexes.len).sort((a,b)=>a-b) } + set ['indexes'](indexes) { return this._indexes = indexes } + ['highlight'](open, close) { return highlight(this, open, close) } + get ['score']() { return normalizeScore(this._score) } + set ['score'](score) { this._score = denormalizeScore(score) } +} + +class KeysResult extends Array { + get ['score']() { return normalizeScore(this._score) } + set ['score'](score) { this._score = denormalizeScore(score) } +} + +var new_result = (target, options) => { + const result = new Result() + result['target'] = target + result['obj'] = options.obj ?? NULL + result._score = options._score ?? NEGATIVE_INFINITY + result._indexes = options._indexes ?? [] + result._targetLower = options._targetLower ?? '' + result._targetLowerCodes = options._targetLowerCodes ?? NULL + result._nextBeginningIndexes = options._nextBeginningIndexes ?? NULL + result._bitflags = options._bitflags ?? 0 + return result +} + + +var normalizeScore = score => { + if(score === NEGATIVE_INFINITY) return 0 + if(score > 1) return score + return Math.E ** ( ((-score + 1)**.04307 - 1) * -2) +} +var denormalizeScore = normalizedScore => { + if(normalizedScore === 0) return NEGATIVE_INFINITY + if(normalizedScore > 1) return normalizedScore + return 1 - Math.pow((Math.log(normalizedScore) / -2 + 1), 1 / 0.04307) +} + + +var prepareSearch = (search) => { + if(typeof search === 'number') search = ''+search + else if(typeof search !== 'string') search = '' + search = search.trim() + var info = prepareLowerInfo(search) + + var spaceSearches = [] + if(info.containsSpace) { + var searches = search.split(/\s+/) + searches = [...new Set(searches)] // distinct + for(var i=0; i { + if(target.length > 999) return prepare(target) // don't cache huge targets + var targetPrepared = preparedCache.get(target) + if(targetPrepared !== undefined) return targetPrepared + targetPrepared = prepare(target) + preparedCache.set(target, targetPrepared) + return targetPrepared +} +var getPreparedSearch = (search) => { + if(search.length > 999) return prepareSearch(search) // don't cache huge searches + var searchPrepared = preparedSearchCache.get(search) + if(searchPrepared !== undefined) return searchPrepared + searchPrepared = prepareSearch(search) + preparedSearchCache.set(search, searchPrepared) + return searchPrepared +} + + +var all = (targets, options) => { + var results = []; results.total = targets.length // this total can be wrong if some targets are skipped + + var limit = options?.limit || INFINITY + + if(options?.key) { + for(var i=0;i= limit) return results + } + } else if(options?.keys) { + for(var i=0;i= 0; --keyI) { + var target = getValue(obj, options.keys[keyI]) + if(!target) { objResults[keyI] = noTarget; continue } + if(!isPrepared(target)) target = getPrepared(target) + target._score = NEGATIVE_INFINITY + target._indexes.len = 0 + objResults[keyI] = target + } + objResults.obj = obj + objResults._score = NEGATIVE_INFINITY + results.push(objResults); if(results.length >= limit) return results + } + } else { + for(var i=0;i= limit) return results + } + } + + return results +} + + +var algorithm = (preparedSearch, prepared, allowSpaces=false, allowPartialMatch=false) => { + if(allowSpaces===false && preparedSearch.containsSpace) return algorithmSpaces(preparedSearch, prepared, allowPartialMatch) + + var searchLower = preparedSearch._lower + var searchLowerCodes = preparedSearch.lowerCodes + var searchLowerCode = searchLowerCodes[0] + var targetLowerCodes = prepared._targetLowerCodes + var searchLen = searchLowerCodes.length + var targetLen = targetLowerCodes.length + var searchI = 0 // where we at + var targetI = 0 // where you at + var matchesSimpleLen = 0 + + // very basic fuzzy match; to remove non-matching targets ASAP! + // walk through target. find sequential matches. + // if all chars aren't found then exit + for(;;) { + var isMatch = searchLowerCode === targetLowerCodes[targetI] + if(isMatch) { + matchesSimple[matchesSimpleLen++] = targetI + ++searchI; if(searchI === searchLen) break + searchLowerCode = searchLowerCodes[searchI] + } + ++targetI; if(targetI >= targetLen) return NULL // Failed to find searchI + } + + var searchI = 0 + var successStrict = false + var matchesStrictLen = 0 + + var nextBeginningIndexes = prepared._nextBeginningIndexes + if(nextBeginningIndexes === NULL) nextBeginningIndexes = prepared._nextBeginningIndexes = prepareNextBeginningIndexes(prepared.target) + targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1] + + // Our target string successfully matched all characters in sequence! + // Let's try a more advanced and strict test to improve the score + // only count it as a match if it's consecutive or a beginning character! + var backtrackCount = 0 + if(targetI !== targetLen) for(;;) { + if(targetI >= targetLen) { + // We failed to find a good spot for this search char, go back to the previous search char and force it forward + if(searchI <= 0) break // We failed to push chars forward for a better match + + ++backtrackCount; if(backtrackCount > 200) break // exponential backtracking is taking too long, just give up and return a bad match + + --searchI + var lastMatch = matchesStrict[--matchesStrictLen] + targetI = nextBeginningIndexes[lastMatch] + + } else { + var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI] + if(isMatch) { + matchesStrict[matchesStrictLen++] = targetI + ++searchI; if(searchI === searchLen) { successStrict = true; break } + ++targetI + } else { + targetI = nextBeginningIndexes[targetI] + } + } + } + + // check if it's a substring match + var substringIndex = searchLen <= 1 ? -1 : prepared._targetLower.indexOf(searchLower, matchesSimple[0]) // perf: this is slow + var isSubstring = !!~substringIndex + var isSubstringBeginning = !isSubstring ? false : substringIndex===0 || prepared._nextBeginningIndexes[substringIndex-1] === substringIndex + + // if it's a substring match but not at a beginning index, let's try to find a substring starting at a beginning index for a better score + if(isSubstring && !isSubstringBeginning) { + for(var i=0; i { + var score = 0 + + var extraMatchGroupCount = 0 + for(var i = 1; i < searchLen; ++i) { + if(matches[i] - matches[i-1] !== 1) {score -= matches[i]; ++extraMatchGroupCount} + } + var unmatchedDistance = matches[searchLen-1] - matches[0] - (searchLen-1) + + score -= (12+unmatchedDistance) * extraMatchGroupCount // penality for more groups + + if(matches[0] !== 0) score -= matches[0]*matches[0]*.2 // penality for not starting near the beginning + + if(!successStrict) { + score *= 1000 + } else { + // successStrict on a target with too many beginning indexes loses points for being a bad target + var uniqueBeginningIndexes = 1 + for(var i = nextBeginningIndexes[0]; i < targetLen; i=nextBeginningIndexes[i]) ++uniqueBeginningIndexes + + if(uniqueBeginningIndexes > 24) score *= (uniqueBeginningIndexes-24)*10 // quite arbitrary numbers here ... + } + + score -= (targetLen - searchLen)/2 // penality for longer targets + + if(isSubstring) score /= 1+searchLen*searchLen*1 // bonus for being a full substring + if(isSubstringBeginning) score /= 1+searchLen*searchLen*1 // bonus for substring starting on a beginningIndex + + score -= (targetLen - searchLen)/2 // penality for longer targets + + return score + } + + if(!successStrict) { + if(isSubstring) for(var i=0; i { + var seen_indexes = new Set() + var score = 0 + var result = NULL + + var first_seen_index_last_search = 0 + var searches = preparedSearch.spaceSearches + var searchesLen = searches.length + var changeslen = 0 + + // Return _nextBeginningIndexes back to its normal state + var resetNextBeginningIndexes = () => { + for(let i=changeslen-1; i>=0; i--) target._nextBeginningIndexes[nextBeginningIndexesChanges[i*2 + 0]] = nextBeginningIndexesChanges[i*2 + 1] + } + + var hasAtLeast1Match = false + for(var i=0; i=0; i--) { + if(toReplace !== target._nextBeginningIndexes[i]) break + target._nextBeginningIndexes[i] = newBeginningIndex + nextBeginningIndexesChanges[changeslen*2 + 0] = i + nextBeginningIndexesChanges[changeslen*2 + 1] = toReplace + changeslen++ + } + } + } + + score += result._score / searchesLen + allowPartialMatchScores[i] = result._score / searchesLen + + // dock points based on order otherwise "c man" returns Manifest.cpp instead of CheatManager.h + if(result._indexes[0] < first_seen_index_last_search) { + score -= (first_seen_index_last_search - result._indexes[0]) * 2 + } + first_seen_index_last_search = result._indexes[0] + + for(var j=0; j score) { + if(allowPartialMatch) { + for(var i=0; i str.replace(/\p{Script=Latin}+/gu, match => match.normalize('NFD')).replace(/[\u0300-\u036f]/g, '') + +var prepareLowerInfo = (str) => { + str = remove_accents(str) + var strLen = str.length + var lower = str.toLowerCase() + var lowerCodes = [] // new Array(strLen) sparse array is too slow + var bitflags = 0 + var containsSpace = false // space isn't stored in bitflags because of how searching with a space works + + for(var i = 0; i < strLen; ++i) { + var lowerCode = lowerCodes[i] = lower.charCodeAt(i) + + if(lowerCode === 32) { + containsSpace = true + continue // it's important that we don't set any bitflags for space + } + + var bit = lowerCode>=97&&lowerCode<=122 ? lowerCode-97 // alphabet + : lowerCode>=48&&lowerCode<=57 ? 26 // numbers + // 3 bits available + : lowerCode<=127 ? 30 // other ascii + : 31 // other utf8 + bitflags |= 1< { + var targetLen = target.length + var beginningIndexes = []; var beginningIndexesLen = 0 + var wasUpper = false + var wasAlphanum = false + for(var i = 0; i < targetLen; ++i) { + var targetCode = target.charCodeAt(i) + var isUpper = targetCode>=65&&targetCode<=90 + var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57 + var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum + wasUpper = isUpper + wasAlphanum = isAlphanum + if(isBeginning) beginningIndexes[beginningIndexesLen++] = i + } + return beginningIndexes +} +var prepareNextBeginningIndexes = (target) => { + target = remove_accents(target) + var targetLen = target.length + var beginningIndexes = prepareBeginningIndexes(target) + var nextBeginningIndexes = [] // new Array(targetLen) sparse array is too slow + var lastIsBeginning = beginningIndexes[0] + var lastIsBeginningI = 0 + for(var i = 0; i < targetLen; ++i) { + if(lastIsBeginning > i) { + nextBeginningIndexes[i] = lastIsBeginning + } else { + lastIsBeginning = beginningIndexes[++lastIsBeginningI] + nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning + } + } + return nextBeginningIndexes +} + +var preparedCache = new Map() +var preparedSearchCache = new Map() + +// the theory behind these being globals is to reduce garbage collection by not making new arrays +var matchesSimple = []; var matchesStrict = [] +var nextBeginningIndexesChanges = [] // allows straw berry to match strawberry well, by modifying the end of a substring to be considered a beginning index for the rest of the search +var keysSpacesBestScores = []; var allowPartialMatchScores = [] +var tmpTargets = []; var tmpResults = [] + +// prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop] +// prop = 'key1.key2' 10ms +// prop = ['key1', 'key2'] 27ms +// prop = obj => obj.tags.join() ??ms +var getValue = (obj, prop) => { + var tmp = obj[prop]; if(tmp !== undefined) return tmp + if(typeof prop === 'function') return prop(obj) // this should run first. but that makes string props slower + var segs = prop + if(!Array.isArray(prop)) segs = prop.split('.') + var len = segs.length + var i = -1 + while (obj && (++i < len)) obj = obj[segs[i]] + return obj +} + +var isPrepared = (x) => { return typeof x === 'object' && typeof x._bitflags === 'number' } +var INFINITY = Infinity; var NEGATIVE_INFINITY = -INFINITY +var noResults = []; noResults.total = 0 +var NULL = null + +var noTarget = prepare('') + +// Hacked version of https://github.com/lemire/FastPriorityQueue.js +var fastpriorityqueue=r=>{var e=[],o=0,a={},v=r=>{for(var a=0,v=e[a],c=1;c>1]=e[a],c=1+(a<<1)}for(var f=a-1>>1;a>0&&v._score>1)e[a]=e[f];e[a]=v};return a.add=(r=>{var a=o;e[o++]=r;for(var v=a-1>>1;a>0&&r._score>1)e[a]=e[v];e[a]=r}),a.poll=(r=>{if(0!==o){var a=e[0];return e[0]=e[--o],v(),a}}),a.peek=(r=>{if(0!==o)return e[0]}),a.replaceTop=(r=>{e[0]=r,v()}),a} +var q = fastpriorityqueue() // reuse this + diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/scripts/fzf.js b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/fzf.js new file mode 100644 index 0000000..995a093 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/fzf.js @@ -0,0 +1,1307 @@ +.pragma library + +/* +https://github.com/ajitid/fzf-for-js + +BSD 3-Clause License + +Copyright (c) 2021, Ajit +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +const normalized = { + 216: "O", + 223: "s", + 248: "o", + 273: "d", + 295: "h", + 305: "i", + 320: "l", + 322: "l", + 359: "t", + 383: "s", + 384: "b", + 385: "B", + 387: "b", + 390: "O", + 392: "c", + 393: "D", + 394: "D", + 396: "d", + 398: "E", + 400: "E", + 402: "f", + 403: "G", + 407: "I", + 409: "k", + 410: "l", + 412: "M", + 413: "N", + 414: "n", + 415: "O", + 421: "p", + 427: "t", + 429: "t", + 430: "T", + 434: "V", + 436: "y", + 438: "z", + 477: "e", + 485: "g", + 544: "N", + 545: "d", + 549: "z", + 564: "l", + 565: "n", + 566: "t", + 567: "j", + 570: "A", + 571: "C", + 572: "c", + 573: "L", + 574: "T", + 575: "s", + 576: "z", + 579: "B", + 580: "U", + 581: "V", + 582: "E", + 583: "e", + 584: "J", + 585: "j", + 586: "Q", + 587: "q", + 588: "R", + 589: "r", + 590: "Y", + 591: "y", + 592: "a", + 593: "a", + 595: "b", + 596: "o", + 597: "c", + 598: "d", + 599: "d", + 600: "e", + 603: "e", + 604: "e", + 605: "e", + 606: "e", + 607: "j", + 608: "g", + 609: "g", + 610: "G", + 613: "h", + 614: "h", + 616: "i", + 618: "I", + 619: "l", + 620: "l", + 621: "l", + 623: "m", + 624: "m", + 625: "m", + 626: "n", + 627: "n", + 628: "N", + 629: "o", + 633: "r", + 634: "r", + 635: "r", + 636: "r", + 637: "r", + 638: "r", + 639: "r", + 640: "R", + 641: "R", + 642: "s", + 647: "t", + 648: "t", + 649: "u", + 651: "v", + 652: "v", + 653: "w", + 654: "y", + 655: "Y", + 656: "z", + 657: "z", + 663: "c", + 665: "B", + 666: "e", + 667: "G", + 668: "H", + 669: "j", + 670: "k", + 671: "L", + 672: "q", + 686: "h", + 867: "a", + 868: "e", + 869: "i", + 870: "o", + 871: "u", + 872: "c", + 873: "d", + 874: "h", + 875: "m", + 876: "r", + 877: "t", + 878: "v", + 879: "x", + 7424: "A", + 7427: "B", + 7428: "C", + 7429: "D", + 7431: "E", + 7432: "e", + 7433: "i", + 7434: "J", + 7435: "K", + 7436: "L", + 7437: "M", + 7438: "N", + 7439: "O", + 7440: "O", + 7441: "o", + 7442: "o", + 7443: "o", + 7446: "o", + 7447: "o", + 7448: "P", + 7449: "R", + 7450: "R", + 7451: "T", + 7452: "U", + 7453: "u", + 7454: "u", + 7455: "m", + 7456: "V", + 7457: "W", + 7458: "Z", + 7522: "i", + 7523: "r", + 7524: "u", + 7525: "v", + 7834: "a", + 7835: "s", + 8305: "i", + 8341: "h", + 8342: "k", + 8343: "l", + 8344: "m", + 8345: "n", + 8346: "p", + 8347: "s", + 8348: "t", + 8580: "c" +}; +for (let i = "\u0300".codePointAt(0); i <= "\u036F".codePointAt(0); ++i) { + const diacritic = String.fromCodePoint(i); + for (const asciiChar of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") { + const withDiacritic = (asciiChar + diacritic).normalize(); + const withDiacriticCodePoint = withDiacritic.codePointAt(0); + if (withDiacriticCodePoint > 126) { + normalized[withDiacriticCodePoint] = asciiChar; + } + } +} +const ranges = { + a: [7844, 7863], + e: [7870, 7879], + o: [7888, 7907], + u: [7912, 7921] +}; +for (const lowerChar of Object.keys(ranges)) { + const upperChar = lowerChar.toUpperCase(); + for (let i = ranges[lowerChar][0]; i <= ranges[lowerChar][1]; ++i) { + normalized[i] = i % 2 === 0 ? upperChar : lowerChar; + } +} +function normalizeRune(rune) { + if (rune < 192 || rune > 8580) { + return rune; + } + const normalizedChar = normalized[rune]; + if (normalizedChar !== void 0) + return normalizedChar.codePointAt(0); + return rune; +} +function toShort(number) { + return number; +} +function toInt(number) { + return number; +} +function maxInt16(num1, num2) { + return num1 > num2 ? num1 : num2; +} +const strToRunes = (str) => str.split("").map((s) => s.codePointAt(0)); +const runesToStr = (runes) => runes.map((r) => String.fromCodePoint(r)).join(""); +const whitespaceRunes = new Set( + " \f\n\r \v\xA0\u1680\u2028\u2029\u202F\u205F\u3000\uFEFF".split("").map((v) => v.codePointAt(0)) +); +for (let codePoint = "\u2000".codePointAt(0); codePoint <= "\u200A".codePointAt(0); codePoint++) { + whitespaceRunes.add(codePoint); +} +const isWhitespace = (rune) => whitespaceRunes.has(rune); +const whitespacesAtStart = (runes) => { + let whitespaces = 0; + for (const rune of runes) { + if (isWhitespace(rune)) + whitespaces++; + else + break; + } + return whitespaces; +}; +const whitespacesAtEnd = (runes) => { + let whitespaces = 0; + for (let i = runes.length - 1; i >= 0; i--) { + if (isWhitespace(runes[i])) + whitespaces++; + else + break; + } + return whitespaces; +}; +const MAX_ASCII = "\x7F".codePointAt(0); +const CAPITAL_A_RUNE = "A".codePointAt(0); +const CAPITAL_Z_RUNE = "Z".codePointAt(0); +const SMALL_A_RUNE = "a".codePointAt(0); +const SMALL_Z_RUNE = "z".codePointAt(0); +const NUMERAL_ZERO_RUNE = "0".codePointAt(0); +const NUMERAL_NINE_RUNE = "9".codePointAt(0); +function indexAt(index, max, forward) { + if (forward) { + return index; + } + return max - index - 1; +} +const SCORE_MATCH = 16, SCORE_GAP_START = -3, SCORE_GAP_EXTENTION = -1, BONUS_BOUNDARY = SCORE_MATCH / 2, BONUS_NON_WORD = SCORE_MATCH / 2, BONUS_CAMEL_123 = BONUS_BOUNDARY + SCORE_GAP_EXTENTION, BONUS_CONSECUTIVE = -(SCORE_GAP_START + SCORE_GAP_EXTENTION), BONUS_FIRST_CHAR_MULTIPLIER = 2; +function createPosSet(withPos) { + if (withPos) { + return /* @__PURE__ */ new Set(); + } + return null; +} +function alloc16(offset, slab2, size) { + if (slab2 !== null && slab2.i16.length > offset + size) { + const subarray = slab2.i16.subarray(offset, offset + size); + return [offset + size, subarray]; + } + return [offset, new Int16Array(size)]; +} +function alloc32(offset, slab2, size) { + if (slab2 !== null && slab2.i32.length > offset + size) { + const subarray = slab2.i32.subarray(offset, offset + size); + return [offset + size, subarray]; + } + return [offset, new Int32Array(size)]; +} +function charClassOfAscii(rune) { + if (rune >= SMALL_A_RUNE && rune <= SMALL_Z_RUNE) { + return 1; + } else if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { + return 2; + } else if (rune >= NUMERAL_ZERO_RUNE && rune <= NUMERAL_NINE_RUNE) { + return 4; + } else { + return 0; + } +} +function charClassOfNonAscii(rune) { + const char = String.fromCodePoint(rune); + if (char !== char.toUpperCase()) { + return 1; + } else if (char !== char.toLowerCase()) { + return 2; + } else if (char.match(/\p{Number}/gu) !== null) { + return 4; + } else if (char.match(/\p{Letter}/gu) !== null) { + return 3; + } + return 0; +} +function charClassOf(rune) { + if (rune <= MAX_ASCII) { + return charClassOfAscii(rune); + } + return charClassOfNonAscii(rune); +} +function bonusFor(prevClass, currClass) { + if (prevClass === 0 && currClass !== 0) { + return BONUS_BOUNDARY; + } else if (prevClass === 1 && currClass === 2 || prevClass !== 4 && currClass === 4) { + return BONUS_CAMEL_123; + } else if (currClass === 0) { + return BONUS_NON_WORD; + } + return 0; +} +function bonusAt(input, idx) { + if (idx === 0) { + return BONUS_BOUNDARY; + } + return bonusFor(charClassOf(input[idx - 1]), charClassOf(input[idx])); +} +function trySkip(input, caseSensitive, char, from) { + let rest = input.slice(from); + let idx = rest.indexOf(char); + if (idx === 0) { + return from; + } + if (!caseSensitive && char >= SMALL_A_RUNE && char <= SMALL_Z_RUNE) { + if (idx > 0) { + rest = rest.slice(0, idx); + } + const uidx = rest.indexOf(char - 32); + if (uidx >= 0) { + idx = uidx; + } + } + if (idx < 0) { + return -1; + } + return from + idx; +} +function isAscii(runes) { + for (const rune of runes) { + if (rune >= 128) { + return false; + } + } + return true; +} +function asciiFuzzyIndex(input, pattern, caseSensitive) { + if (!isAscii(input)) { + return 0; + } + if (!isAscii(pattern)) { + return -1; + } + let firstIdx = 0, idx = 0; + for (let pidx = 0; pidx < pattern.length; pidx++) { + idx = trySkip(input, caseSensitive, pattern[pidx], idx); + if (idx < 0) { + return -1; + } + if (pidx === 0 && idx > 0) { + firstIdx = idx - 1; + } + idx++; + } + return firstIdx; +} +const fuzzyMatchV2 = (caseSensitive, normalize, forward, input, pattern, withPos, slab2) => { + const M = pattern.length; + if (M === 0) { + return [{ start: 0, end: 0, score: 0 }, createPosSet(withPos)]; + } + const N = input.length; + if (slab2 !== null && N * M > slab2.i16.length) { + return fuzzyMatchV1(caseSensitive, normalize, forward, input, pattern, withPos); + } + const idx = asciiFuzzyIndex(input, pattern, caseSensitive); + if (idx < 0) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + let offset16 = 0, offset32 = 0, H0 = null, C0 = null, B = null, F = null; + [offset16, H0] = alloc16(offset16, slab2, N); + [offset16, C0] = alloc16(offset16, slab2, N); + [offset16, B] = alloc16(offset16, slab2, N); + [offset32, F] = alloc32(offset32, slab2, M); + const [, T] = alloc32(offset32, slab2, N); + for (let i = 0; i < T.length; i++) { + T[i] = input[i]; + } + let maxScore = toShort(0), maxScorePos = 0; + let pidx = 0, lastIdx = 0; + const pchar0 = pattern[0]; + let pchar = pattern[0], prevH0 = toShort(0), prevCharClass = 0, inGap = false; + let Tsub = T.subarray(idx); + let H0sub = H0.subarray(idx).subarray(0, Tsub.length), C0sub = C0.subarray(idx).subarray(0, Tsub.length), Bsub = B.subarray(idx).subarray(0, Tsub.length); + for (let [off, char] of Tsub.entries()) { + let charClass = null; + if (char <= MAX_ASCII) { + charClass = charClassOfAscii(char); + if (!caseSensitive && charClass === 2) { + char += 32; + } + } else { + charClass = charClassOfNonAscii(char); + if (!caseSensitive && charClass === 2) { + char = String.fromCodePoint(char).toLowerCase().codePointAt(0); + } + if (normalize) { + char = normalizeRune(char); + } + } + Tsub[off] = char; + const bonus = bonusFor(prevCharClass, charClass); + Bsub[off] = bonus; + prevCharClass = charClass; + if (char === pchar) { + if (pidx < M) { + F[pidx] = toInt(idx + off); + pidx++; + pchar = pattern[Math.min(pidx, M - 1)]; + } + lastIdx = idx + off; + } + if (char === pchar0) { + const score = SCORE_MATCH + bonus * BONUS_FIRST_CHAR_MULTIPLIER; + H0sub[off] = score; + C0sub[off] = 1; + if (M === 1 && (forward && score > maxScore || !forward && score >= maxScore)) { + maxScore = score; + maxScorePos = idx + off; + if (forward && bonus === BONUS_BOUNDARY) { + break; + } + } + inGap = false; + } else { + if (inGap) { + H0sub[off] = maxInt16(prevH0 + SCORE_GAP_EXTENTION, 0); + } else { + H0sub[off] = maxInt16(prevH0 + SCORE_GAP_START, 0); + } + C0sub[off] = 0; + inGap = true; + } + prevH0 = H0sub[off]; + } + if (pidx !== M) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + if (M === 1) { + const result = { + start: maxScorePos, + end: maxScorePos + 1, + score: maxScore + }; + if (!withPos) { + return [result, null]; + } + const pos2 = /* @__PURE__ */ new Set(); + pos2.add(maxScorePos); + return [result, pos2]; + } + const f0 = F[0]; + const width = lastIdx - f0 + 1; + let H = null; + [offset16, H] = alloc16(offset16, slab2, width * M); + { + const toCopy = H0.subarray(f0, lastIdx + 1); + for (const [i, v] of toCopy.entries()) { + H[i] = v; + } + } + let [, C] = alloc16(offset16, slab2, width * M); + { + const toCopy = C0.subarray(f0, lastIdx + 1); + for (const [i, v] of toCopy.entries()) { + C[i] = v; + } + } + const Fsub = F.subarray(1); + const Psub = pattern.slice(1).slice(0, Fsub.length); + for (const [off, f] of Fsub.entries()) { + let inGap2 = false; + const pchar2 = Psub[off], pidx2 = off + 1, row = pidx2 * width, Tsub2 = T.subarray(f, lastIdx + 1), Bsub2 = B.subarray(f).subarray(0, Tsub2.length), Csub = C.subarray(row + f - f0).subarray(0, Tsub2.length), Cdiag = C.subarray(row + f - f0 - 1 - width).subarray(0, Tsub2.length), Hsub = H.subarray(row + f - f0).subarray(0, Tsub2.length), Hdiag = H.subarray(row + f - f0 - 1 - width).subarray(0, Tsub2.length), Hleft = H.subarray(row + f - f0 - 1).subarray(0, Tsub2.length); + Hleft[0] = 0; + for (const [off2, char] of Tsub2.entries()) { + const col = off2 + f; + let s1 = 0, s2 = 0, consecutive = 0; + if (inGap2) { + s2 = Hleft[off2] + SCORE_GAP_EXTENTION; + } else { + s2 = Hleft[off2] + SCORE_GAP_START; + } + if (pchar2 === char) { + s1 = Hdiag[off2] + SCORE_MATCH; + let b = Bsub2[off2]; + consecutive = Cdiag[off2] + 1; + if (b === BONUS_BOUNDARY) { + consecutive = 1; + } else if (consecutive > 1) { + b = maxInt16(b, maxInt16(BONUS_CONSECUTIVE, B[col - consecutive + 1])); + } + if (s1 + b < s2) { + s1 += Bsub2[off2]; + consecutive = 0; + } else { + s1 += b; + } + } + Csub[off2] = consecutive; + inGap2 = s1 < s2; + const score = maxInt16(maxInt16(s1, s2), 0); + if (pidx2 === M - 1 && (forward && score > maxScore || !forward && score >= maxScore)) { + maxScore = score; + maxScorePos = col; + } + Hsub[off2] = score; + } + } + const pos = createPosSet(withPos); + let j = f0; + if (withPos && pos !== null) { + let i = M - 1; + j = maxScorePos; + let preferMatch = true; + while (true) { + const I = i * width, j0 = j - f0, s = H[I + j0]; + let s1 = 0, s2 = 0; + if (i > 0 && j >= F[i]) { + s1 = H[I - width + j0 - 1]; + } + if (j > F[i]) { + s2 = H[I + j0 - 1]; + } + if (s > s1 && (s > s2 || s === s2 && preferMatch)) { + pos.add(j); + if (i === 0) { + break; + } + i--; + } + preferMatch = C[I + j0] > 1 || I + width + j0 + 1 < C.length && C[I + width + j0 + 1] > 0; + j--; + } + } + return [{ start: j, end: maxScorePos + 1, score: maxScore }, pos]; +}; +function calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, withPos) { + let pidx = 0, score = 0, inGap = false, consecutive = 0, firstBonus = toShort(0); + const pos = createPosSet(withPos); + let prevCharClass = 0; + if (sidx > 0) { + prevCharClass = charClassOf(text[sidx - 1]); + } + for (let idx = sidx; idx < eidx; idx++) { + let rune = text[idx]; + const charClass = charClassOf(rune); + if (!caseSensitive) { + if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { + rune += 32; + } else if (rune > MAX_ASCII) { + rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); + } + } + if (normalize) { + rune = normalizeRune(rune); + } + if (rune === pattern[pidx]) { + if (withPos && pos !== null) { + pos.add(idx); + } + score += SCORE_MATCH; + let bonus = bonusFor(prevCharClass, charClass); + if (consecutive === 0) { + firstBonus = bonus; + } else { + if (bonus === BONUS_BOUNDARY) { + firstBonus = bonus; + } + bonus = maxInt16(maxInt16(bonus, firstBonus), BONUS_CONSECUTIVE); + } + if (pidx === 0) { + score += bonus * BONUS_FIRST_CHAR_MULTIPLIER; + } else { + score += bonus; + } + inGap = false; + consecutive++; + pidx++; + } else { + if (inGap) { + score += SCORE_GAP_EXTENTION; + } else { + score += SCORE_GAP_START; + } + inGap = true; + consecutive = 0; + firstBonus = 0; + } + prevCharClass = charClass; + } + return [score, pos]; +} +function fuzzyMatchV1(caseSensitive, normalize, forward, text, pattern, withPos, slab2) { + if (pattern.length === 0) { + return [{ start: 0, end: 0, score: 0 }, null]; + } + if (asciiFuzzyIndex(text, pattern, caseSensitive) < 0) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + let pidx = 0, sidx = -1, eidx = -1; + const lenRunes = text.length; + const lenPattern = pattern.length; + for (let index = 0; index < lenRunes; index++) { + let rune = text[indexAt(index, lenRunes, forward)]; + if (!caseSensitive) { + if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { + rune += 32; + } else if (rune > MAX_ASCII) { + rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); + } + } + if (normalize) { + rune = normalizeRune(rune); + } + const pchar = pattern[indexAt(pidx, lenPattern, forward)]; + if (rune === pchar) { + if (sidx < 0) { + sidx = index; + } + pidx++; + if (pidx === lenPattern) { + eidx = index + 1; + break; + } + } + } + if (sidx >= 0 && eidx >= 0) { + pidx--; + for (let index = eidx - 1; index >= sidx; index--) { + const tidx = indexAt(index, lenRunes, forward); + let rune = text[tidx]; + if (!caseSensitive) { + if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { + rune += 32; + } else if (rune > MAX_ASCII) { + rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); + } + } + const pidx_ = indexAt(pidx, lenPattern, forward); + const pchar = pattern[pidx_]; + if (rune === pchar) { + pidx--; + if (pidx < 0) { + sidx = index; + break; + } + } + } + if (!forward) { + const sidxTemp = sidx; + sidx = lenRunes - eidx; + eidx = lenRunes - sidxTemp; + } + const [score, pos] = calculateScore( + caseSensitive, + normalize, + text, + pattern, + sidx, + eidx, + withPos + ); + return [{ start: sidx, end: eidx, score }, pos]; + } + return [{ start: -1, end: -1, score: 0 }, null]; +}; +const exactMatchNaive = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { + if (pattern.length === 0) { + return [{ start: 0, end: 0, score: 0 }, null]; + } + const lenRunes = text.length; + const lenPattern = pattern.length; + if (lenRunes < lenPattern) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + if (asciiFuzzyIndex(text, pattern, caseSensitive) < 0) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + let pidx = 0; + let bestPos = -1, bonus = toShort(0), bestBonus = toShort(-1); + for (let index = 0; index < lenRunes; index++) { + const index_ = indexAt(index, lenRunes, forward); + let rune = text[index_]; + if (!caseSensitive) { + if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { + rune += 32; + } else if (rune > MAX_ASCII) { + rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); + } + } + if (normalize) { + rune = normalizeRune(rune); + } + const pidx_ = indexAt(pidx, lenPattern, forward); + const pchar = pattern[pidx_]; + if (pchar === rune) { + if (pidx_ === 0) { + bonus = bonusAt(text, index_); + } + pidx++; + if (pidx === lenPattern) { + if (bonus > bestBonus) { + bestPos = index; + bestBonus = bonus; + } + if (bonus === BONUS_BOUNDARY) { + break; + } + index -= pidx - 1; + pidx = 0; + bonus = 0; + } + } else { + index -= pidx; + pidx = 0; + bonus = 0; + } + } + if (bestPos >= 0) { + let sidx = 0, eidx = 0; + if (forward) { + sidx = bestPos - lenPattern + 1; + eidx = bestPos + 1; + } else { + sidx = lenRunes - (bestPos + 1); + eidx = lenRunes - (bestPos - lenPattern + 1); + } + const [score] = calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false); + return [{ start: sidx, end: eidx, score }, null]; + } + return [{ start: -1, end: -1, score: 0 }, null]; +}; +const prefixMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { + if (pattern.length === 0) { + return [{ start: 0, end: 0, score: 0 }, null]; + } + let trimmedLen = 0; + if (!isWhitespace(pattern[0])) { + trimmedLen = whitespacesAtStart(text); + } + if (text.length - trimmedLen < pattern.length) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + for (const [index, r] of pattern.entries()) { + let rune = text[trimmedLen + index]; + if (!caseSensitive) { + rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); + } + if (normalize) { + rune = normalizeRune(rune); + } + if (rune !== r) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + } + const lenPattern = pattern.length; + const [score] = calculateScore( + caseSensitive, + normalize, + text, + pattern, + trimmedLen, + trimmedLen + lenPattern, + false + ); + return [{ start: trimmedLen, end: trimmedLen + lenPattern, score }, null]; +}; +const suffixMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { + const lenRunes = text.length; + let trimmedLen = lenRunes; + if (pattern.length === 0 || !isWhitespace(pattern[pattern.length - 1])) { + trimmedLen -= whitespacesAtEnd(text); + } + if (pattern.length === 0) { + return [{ start: trimmedLen, end: trimmedLen, score: 0 }, null]; + } + const diff = trimmedLen - pattern.length; + if (diff < 0) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + for (const [index, r] of pattern.entries()) { + let rune = text[index + diff]; + if (!caseSensitive) { + rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); + } + if (normalize) { + rune = normalizeRune(rune); + } + if (rune !== r) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + } + const lenPattern = pattern.length; + const sidx = trimmedLen - lenPattern; + const eidx = trimmedLen; + const [score] = calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false); + return [{ start: sidx, end: eidx, score }, null]; +}; +const equalMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { + const lenPattern = pattern.length; + if (lenPattern === 0) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + let trimmedLen = 0; + if (!isWhitespace(pattern[0])) { + trimmedLen = whitespacesAtStart(text); + } + let trimmedEndLen = 0; + if (!isWhitespace(pattern[lenPattern - 1])) { + trimmedEndLen = whitespacesAtEnd(text); + } + if (text.length - trimmedLen - trimmedEndLen != lenPattern) { + return [{ start: -1, end: -1, score: 0 }, null]; + } + let match = true; + if (normalize) { + const runes = text; + for (const [idx, pchar] of pattern.entries()) { + let rune = runes[trimmedLen + idx]; + if (!caseSensitive) { + rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); + } + if (normalizeRune(pchar) !== normalizeRune(rune)) { + match = false; + break; + } + } + } else { + let runesStr = runesToStr(text).substring(trimmedLen, text.length - trimmedEndLen); + if (!caseSensitive) { + runesStr = runesStr.toLowerCase(); + } + match = runesStr === runesToStr(pattern); + } + if (match) { + return [ + { + start: trimmedLen, + end: trimmedLen + lenPattern, + score: (SCORE_MATCH + BONUS_BOUNDARY) * lenPattern + (BONUS_FIRST_CHAR_MULTIPLIER - 1) * BONUS_BOUNDARY + }, + null + ]; + } + return [{ start: -1, end: -1, score: 0 }, null]; +}; +const SLAB_16_SIZE = 100 * 1024; +const SLAB_32_SIZE = 2048; +function makeSlab(size16, size32) { + return { + i16: new Int16Array(size16), + i32: new Int32Array(size32) + }; +} +const slab = makeSlab(SLAB_16_SIZE, SLAB_32_SIZE); +var TermType = /* @__PURE__ */ ((TermType2) => { + TermType2[TermType2["Fuzzy"] = 0] = "Fuzzy"; + TermType2[TermType2["Exact"] = 1] = "Exact"; + TermType2[TermType2["Prefix"] = 2] = "Prefix"; + TermType2[TermType2["Suffix"] = 3] = "Suffix"; + TermType2[TermType2["Equal"] = 4] = "Equal"; + return TermType2; +})(TermType || {}); +const termTypeMap = { + [0]: fuzzyMatchV2, + [1]: exactMatchNaive, + [2]: prefixMatch, + [3]: suffixMatch, + [4]: equalMatch +}; +function buildPatternForExtendedMatch(fuzzy, caseMode, normalize, str) { + let cacheable = true; + str = str.trimLeft(); + { + const trimmedAtRightStr = str.trimRight(); + if (trimmedAtRightStr.endsWith("\\") && str[trimmedAtRightStr.length] === " ") { + str = trimmedAtRightStr + " "; + } else { + str = trimmedAtRightStr; + } + } + let sortable = false; + let termSets = []; + termSets = parseTerms(fuzzy, caseMode, normalize, str); + Loop: + for (const termSet of termSets) { + for (const [idx, term] of termSet.entries()) { + if (!term.inv) { + sortable = true; + } + if (!cacheable || idx > 0 || term.inv || fuzzy && term.typ !== 0 || !fuzzy && term.typ !== 1) { + cacheable = false; + if (sortable) { + break Loop; + } + } + } + } + return { + str, + termSets, + sortable, + cacheable, + fuzzy + }; +} +function parseTerms(fuzzy, caseMode, normalize, str) { + str = str.replace(/\\ /g, " "); + const tokens = str.split(/ +/); + const sets = []; + let set = []; + let switchSet = false; + let afterBar = false; + for (const token of tokens) { + let typ = 0, inv = false, text = token.replace(/\t/g, " "); + const lowerText = text.toLowerCase(); + const caseSensitive = caseMode === "case-sensitive" || caseMode === "smart-case" && text !== lowerText; + const normalizeTerm = normalize && lowerText === runesToStr(strToRunes(lowerText).map(normalizeRune)); + if (!caseSensitive) { + text = lowerText; + } + if (!fuzzy) { + typ = 1; + } + if (set.length > 0 && !afterBar && text === "|") { + switchSet = false; + afterBar = true; + continue; + } + afterBar = false; + if (text.startsWith("!")) { + inv = true; + typ = 1; + text = text.substring(1); + } + if (text !== "$" && text.endsWith("$")) { + typ = 3; + text = text.substring(0, text.length - 1); + } + if (text.startsWith("'")) { + if (fuzzy && !inv) { + typ = 1; + } else { + typ = 0; + } + text = text.substring(1); + } else if (text.startsWith("^")) { + if (typ === 3) { + typ = 4; + } else { + typ = 2; + } + text = text.substring(1); + } + if (text.length > 0) { + if (switchSet) { + sets.push(set); + set = []; + } + let textRunes = strToRunes(text); + if (normalizeTerm) { + textRunes = textRunes.map(normalizeRune); + } + set.push({ + typ, + inv, + text: textRunes, + caseSensitive, + normalize: normalizeTerm + }); + switchSet = true; + } + } + if (set.length > 0) { + sets.push(set); + } + return sets; +} +const buildPatternForBasicMatch = (query, casing, normalize) => { + let caseSensitive = false; + switch (casing) { + case "smart-case": + if (query.toLowerCase() !== query) { + caseSensitive = true; + } + break; + case "case-sensitive": + caseSensitive = true; + break; + case "case-insensitive": + query = query.toLowerCase(); + caseSensitive = false; + break; + } + let queryRunes = strToRunes(query); + if (normalize) { + queryRunes = queryRunes.map(normalizeRune); + } + return { + queryRunes, + caseSensitive + }; +}; +function iter(algoFn, tokens, caseSensitive, normalize, forward, pattern, slab2) { + for (const part of tokens) { + const [res, pos] = algoFn(caseSensitive, normalize, forward, part.text, pattern, true, slab2); + if (res.start >= 0) { + const sidx = res.start + part.prefixLength; + const eidx = res.end + part.prefixLength; + if (pos !== null) { + const newPos = /* @__PURE__ */ new Set(); + pos.forEach((v) => newPos.add(part.prefixLength + v)); + return [[sidx, eidx], res.score, newPos]; + } + return [[sidx, eidx], res.score, pos]; + } + } + return [[-1, -1], 0, null]; +} +function computeExtendedMatch(text, pattern, fuzzyAlgo, forward) { + const input = [ + { + text, + prefixLength: 0 + } + ]; + const offsets = []; + let totalScore = 0; + const allPos = /* @__PURE__ */ new Set(); + for (const termSet of pattern.termSets) { + let offset = [0, 0]; + let currentScore = 0; + let matched = false; + for (const term of termSet) { + let algoFn = termTypeMap[term.typ]; + if (term.typ === TermType.Fuzzy) { + algoFn = fuzzyAlgo; + } + const [off, score, pos] = iter( + algoFn, + input, + term.caseSensitive, + term.normalize, + forward, + term.text, + slab + ); + const sidx = off[0]; + if (sidx >= 0) { + if (term.inv) { + continue; + } + offset = off; + currentScore = score; + matched = true; + if (pos !== null) { + pos.forEach((v) => allPos.add(v)); + } else { + for (let idx = off[0]; idx < off[1]; ++idx) { + allPos.add(idx); + } + } + break; + } else if (term.inv) { + offset = [0, 0]; + currentScore = 0; + matched = true; + continue; + } + } + if (matched) { + offsets.push(offset); + totalScore += currentScore; + } + } + return { offsets, totalScore, allPos }; +} +function getResultFromScoreMap(scoreMap, limit) { + const scoresInDesc = Object.keys(scoreMap).map((v) => parseInt(v, 10)).sort((a, b) => b - a); + let result = []; + for (const score of scoresInDesc) { + result = result.concat(scoreMap[score]); + if (result.length >= limit) { + break; + } + } + return result; +} +function getBasicMatchIter(scoreMap, queryRunes, caseSensitive) { + return (idx) => { + const itemRunes = this.runesList[idx]; + if (queryRunes.length > itemRunes.length) + return; + let [match, positions] = this.algoFn( + caseSensitive, + this.opts.normalize, + this.opts.forward, + itemRunes, + queryRunes, + true, + slab + ); + if (match.start === -1) + return; + if (this.opts.fuzzy === false) { + positions = /* @__PURE__ */ new Set(); + for (let position = match.start; position < match.end; ++position) { + positions.add(position); + } + } + const scoreKey = this.opts.sort ? match.score : 0; + if (scoreMap[scoreKey] === void 0) { + scoreMap[scoreKey] = []; + } + scoreMap[scoreKey].push(Object.assign({ + item: this.items[idx], + positions: positions != null ? positions : /* @__PURE__ */ new Set() + }, match)); + }; +} +function getExtendedMatchIter(scoreMap, pattern) { + return (idx) => { + const runes = this.runesList[idx]; + const match = computeExtendedMatch(runes, pattern, this.algoFn, this.opts.forward); + if (match.offsets.length !== pattern.termSets.length) + return; + let sidx = -1, eidx = -1; + if (match.allPos.size > 0) { + sidx = Math.min(...match.allPos); + eidx = Math.max(...match.allPos) + 1; + } + const scoreKey = this.opts.sort ? match.totalScore : 0; + if (scoreMap[scoreKey] === void 0) { + scoreMap[scoreKey] = []; + } + scoreMap[scoreKey].push({ + score: match.totalScore, + item: this.items[idx], + positions: match.allPos, + start: sidx, + end: eidx + }); + }; +} +function basicMatch(query) { + const { queryRunes, caseSensitive } = buildPatternForBasicMatch( + query, + this.opts.casing, + this.opts.normalize + ); + const scoreMap = {}; + const iter2 = getBasicMatchIter.bind(this)( + scoreMap, + queryRunes, + caseSensitive + ); + for (let i = 0, len = this.runesList.length; i < len; ++i) { + iter2(i); + } + return getResultFromScoreMap(scoreMap, this.opts.limit); +} +function extendedMatch(query) { + const pattern = buildPatternForExtendedMatch( + Boolean(this.opts.fuzzy), + this.opts.casing, + this.opts.normalize, + query + ); + const scoreMap = {}; + const iter2 = getExtendedMatchIter.bind(this)(scoreMap, pattern); + for (let i = 0, len = this.runesList.length; i < len; ++i) { + iter2(i); + } + return getResultFromScoreMap(scoreMap, this.opts.limit); +} +const defaultOpts = { + limit: Infinity, + selector: (v) => v, + casing: "smart-case", + normalize: true, + fuzzy: "v2", + tiebreakers: [], + sort: true, + forward: true, + match: basicMatch +}; +class Finder { + constructor(list, ...optionsTuple) { + this.opts = Object.assign(defaultOpts, optionsTuple[0]); + this.items = list; + this.runesList = list.map((item) => strToRunes(this.opts.selector(item).normalize())); + this.algoFn = exactMatchNaive; + switch (this.opts.fuzzy) { + case "v2": + this.algoFn = fuzzyMatchV2; + break; + case "v1": + this.algoFn = fuzzyMatchV1; + break; + } + } + find(query) { + if (query.length === 0 || this.items.length === 0) + return this.items.slice(0, this.opts.limit).map(createResultItemWithEmptyPos); + query = query.normalize(); + let result = this.opts.match.bind(this)(query); + return postProcessResultItems(result, this.opts); + } +} +function createResultItemWithEmptyPos(item) { + return ({ + item, + start: -1, + end: -1, + score: 0, + positions: /* @__PURE__ */ new Set() + }) +}; +function postProcessResultItems(result, opts) { + if (opts.sort) { + const { selector } = opts; + result.sort((a, b) => { + if (a.score === b.score) { + for (const tiebreaker of opts.tiebreakers) { + const diff = tiebreaker(a, b, selector); + if (diff !== 0) { + return diff; + } + } + } + return 0; + }); + } + if (Number.isFinite(opts.limit)) { + result.splice(opts.limit); + } + return result; +} +function byLengthAsc(a, b, selector) { + return selector(a.item).length - selector(b.item).length; +} +function byStartAsc(a, b) { + return a.start - b.start; +} diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/scripts/install-bin.sh b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/install-bin.sh new file mode 100644 index 0000000..75bb95a --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/install-bin.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" +SCRIPT="./zshell.sh" + +prepare_binary() { + sed -ir "s|QML_ROOT=.*|QML_ROOT=${SCRIPT_DIR}/..|" "$SCRIPT" +} + +main() { + prepare_binary + + sudo cp "$SCRIPT" /usr/bin/zshell +} + +main "$@" diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/scripts/update.sh b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/update.sh new file mode 100644 index 0000000..3108bdb --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/scripts/update.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +OS="arch" +if [[ $(ls ./tmp) ]]; then + exec mkdir ./tmp +fi + +cd ./tmp + +main() { + local OPTARG OPTIND opt + while getopts "arch:nix:" opt; do + case "$opt" in + arch) OS=$OPTARG ;; + nix) OS=$OPTARG ;; + *) fatal 'bad option' ;; + esac + done + + if [[ $OS = "arch" ]]; then + exec yay -Sy + elif [[ $OS = "nix" ]]; then + exec nixos-rebuild build --flake $HOME/Gits/NixOS/#nixos + PKGS=$(exec nix store diff-closures /run/current-system ./result) + fi +} + +main "$@" diff --git a/pkg/zshell/etc/xdg/quickshell/zshell/shell.qml b/pkg/zshell/etc/xdg/quickshell/zshell/shell.qml new file mode 100644 index 0000000..61e3f61 --- /dev/null +++ b/pkg/zshell/etc/xdg/quickshell/zshell/shell.qml @@ -0,0 +1,26 @@ +//@ pragma UseQApplication +//@ pragma Env QSG_RENDER_LOOP=threaded +//@ pragma Env QS_NO_RELOAD_POPUP=1 +import Quickshell +import qs.Modules +import qs.Modules.Wallpaper +import qs.Modules.Lock as Lock +import qs.Drawers +import qs.Helpers +import qs.Modules.Polkit + +ShellRoot { + Bar {} + Wallpaper {} + AreaPicker {} + Lock.Lock { + id: lock + } + + Shortcuts {} + Lock.IdleInhibitor { + lock: lock + } + + Polkit {} +} diff --git a/pkg/zshell/usr/bin/zshell-cli b/pkg/zshell/usr/bin/zshell-cli new file mode 100755 index 0000000..1677e61 --- /dev/null +++ b/pkg/zshell/usr/bin/zshell-cli @@ -0,0 +1,8 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from zshell import main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(main()) diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/METADATA b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/METADATA new file mode 100644 index 0000000..782135e --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/METADATA @@ -0,0 +1,7 @@ +Metadata-Version: 2.4 +Name: zshell +Version: 0.1.0 +Requires-Python: >=3.13 +Requires-Dist: materialyoucolor +Requires-Dist: pillow +Requires-Dist: typer diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/RECORD b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/RECORD new file mode 100644 index 0000000..2e4e00a --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/RECORD @@ -0,0 +1,39 @@ +../../../bin/zshell-cli,sha256=-Gj5CBazXzm9TGR1Q7Udds9-CFVkWnQSsZFKsgEwgEk,204 +zshell/__init__.py,sha256=1ltlLAf8kdDhH3T-M-7gckmieUAtf57DesH1sY6Vm10,346 +zshell/__main__.py,sha256=5BjNuyet8AY-POwoF5rGt722rHQ7tJ0Vf0UFUfzzi-I,58 +zshell/assets/schemes/catppuccin/frappe/dark.txt,sha256=EJaYiulbKFHKWn9NwTEw7wTYr0LXI6ucjvPlO9H99Nc,2105 +zshell/assets/schemes/catppuccin/latte/light.txt,sha256=_EnXm3HTPqIf5A2yVQpfBoUz05zt8cIiSbgI2jkESeI,2105 +zshell/assets/schemes/catppuccin/macchiato/dark.txt,sha256=k7aRIPd7CNfQJy019z06MqIYX_fPw_ivM9dU-0L0mnE,2105 +zshell/assets/schemes/catppuccin/mocha/dark.txt,sha256=MwsDEYlBCKesUnibWuXqxdTcUgeFNUq4_dFyQ8qMROo,2105 +zshell/assets/schemes/darkgreen/hard/dark.txt,sha256=tnyzeiAEffnepOhAduCgh9mbAtaVe0u-PGu2AqYInj0,2105 +zshell/assets/schemes/darkgreen/medium/dark.txt,sha256=Yy24glSq_Ilk84_s8WriW8vIBPEKSvA2c5m9-pYTRps,2105 +zshell/assets/schemes/dracula/medium/dark.txt,sha256=vouQnReE5AwNATnANVM_5bzy4pS0kosJPoaGEYqdwD8,2106 +zshell/assets/schemes/everblush/medium/dark.txt,sha256=Rs2AcX-zepqkb8DO-jXBDHPERNd_i1i2sb3srugaZ7M,2106 +zshell/assets/schemes/everforest/hard/dark.txt,sha256=ismYwiBGW1UKHoKM80Ps1eOSMDM_Y2JlNZV5YP_GpoE,2106 +zshell/assets/schemes/everforest/medium/dark.txt,sha256=vfec052Chlc1eHjd7cK9FgawjlDVKkvSnwOiAjlpVJI,2106 +zshell/assets/schemes/everforest/medium/light.txt,sha256=nGnbytselRSfpwEog5glyePuxP0BcdO29NtwM3WnaXQ,2106 +zshell/assets/schemes/everforest/soft/dark.txt,sha256=CipE0CKsawCrNhREUBKaySHNtdufZptaHyikjbmOy6Y,2106 +zshell/assets/schemes/gruvbox/hard/dark.txt,sha256=BOn0UG09yXgr4faPZdxlaMV5-iF1-8TvtRIGK0xHGS8,2105 +zshell/assets/schemes/gruvbox/hard/light.txt,sha256=cj-RXXFIvYP_AoyL3TrdWSjDXOy5KX1IMSm64tnD6us,2105 +zshell/assets/schemes/gruvbox/medium/dark.txt,sha256=0CPWIcjnTCYLUcne5jsEGO9ScU3mAEt1eWhlM4fcx38,2105 +zshell/assets/schemes/gruvbox/medium/light.txt,sha256=NEXhNGbvT9lyKvMwlKN-B3Z8y2T_8qXTDIaC8ws-bO4,2105 +zshell/assets/schemes/gruvbox/soft/dark.txt,sha256=LEzJP0O3SWbD-TDXMWRt1LiiBbOEl8CK-OZDQhbOrjM,2105 +zshell/assets/schemes/gruvbox/soft/light.txt,sha256=gtwb7UakATmh2Yx_6a6gfNh04VeBiLxN3excF0y1Big,2105 +zshell/assets/schemes/nord/medium/dark.txt,sha256=nBI9Qdfv-TnSVTo3cH0kF8cyhoIchxv4V1czZL8JIa4,2106 +zshell/assets/schemes/oldworld/default/dark.txt,sha256=5wVTJ-c5G2JHiam9DWzd1E5_gc69OjuYSvyj1-ZwnEk,2105 +zshell/assets/schemes/onedark/default/dark.txt,sha256=nx1GWuBYafNbXNwNvzfiSQ-LZVB8jzryRI9oRNrafg0,2105 +zshell/assets/schemes/rosepine/dawn/light.txt,sha256=B_0LL3gtDaeQ3lvR68WKHDQzlttRiKbYAmH2naPgic8,2105 +zshell/assets/schemes/rosepine/main/dark.txt,sha256=VVJskohJXdY3A3RuIte61Sy8nuKRA6HE95TwVI9pXHo,2105 +zshell/assets/schemes/rosepine/moon/dark.txt,sha256=6Lqnt6_49ZPFEUpiqYAfeMUnhqMbIaGRvlm9t1mgbk4,2105 +zshell/assets/schemes/shadotheme/default/dark.txt,sha256=GWNvDtY1niLmgP1Z4T477K18qOafuhH4leOWCyCc_u0,2105 +zshell/assets/schemes/solarized/medium/dark.txt,sha256=gW3Y_VCZ7jS68bv_zbjlZPKChGJftK1sK40fJHU94fM,2106 +zshell/assets/schemes/tokyonight/medium/dark.txt,sha256=4hHIgaFga9fm0aG0f49WO0RyWm_LTESbZgOUprMBRWk,2106 +zshell/subcommands/scheme.py,sha256=cUYH23s9TMbel5DiR8ITsCYHB_qeUv0nI3k2qNfKo3w,5205 +zshell/subcommands/screenshot.py,sha256=ajAqL_-pFQGiJLYItMBfgY3RK6xoJNIqNn7erHv-TMY,358 +zshell/subcommands/shell.py,sha256=MSUF5r99gehIm7qZiAnSwkavPiQPkxo7niNaMyVGGFs,775 +zshell/subcommands/wallpaper.py,sha256=lDvi2HHt4V6AX4WSmItJ0q8DE0J0dRlMThqgi2qOyPk,919 +zshell/utils/schemepalettes.py,sha256=M9QzRBQ4D5LHCqtQZd_TUye_G6YVnLaxhWMwVgqA7Jw,669 +zshell-0.1.0.dist-info/METADATA,sha256=5NZkc3MyTep_DcTHFtlcpxckYPL0HEk1O2Oi2qbsGfQ,149 +zshell-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87 +zshell-0.1.0.dist-info/entry_points.txt,sha256=XgylnsqeATQRtH22HceLFQHEB37UY6UHtYIcWfNxDx8,43 +zshell-0.1.0.dist-info/RECORD,, diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/WHEEL b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/WHEEL new file mode 100644 index 0000000..ae8ec1b --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.28.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/entry_points.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/entry_points.txt new file mode 100644 index 0000000..34d7089 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell-0.1.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +zshell-cli = zshell:main diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__init__.py b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__init__.py new file mode 100644 index 0000000..2dee338 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__init__.py @@ -0,0 +1,14 @@ +from __future__ import annotations +import typer +from zshell.subcommands import shell, scheme, screenshot, wallpaper + +app = typer.Typer() + +app.add_typer(shell.app, name="shell") +app.add_typer(scheme.app, name="scheme") +app.add_typer(screenshot.app, name="screenshot") +app.add_typer(wallpaper.app, name="wallpaper") + + +def main() -> None: + app() diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__main__.py b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__main__.py new file mode 100644 index 0000000..868d99e --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__main__.py @@ -0,0 +1,4 @@ +from . import main + +if __name__ == "__main__": + main() diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__init__.cpython-314.opt-1.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__init__.cpython-314.opt-1.pyc new file mode 100644 index 0000000..5eb78e3 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__init__.cpython-314.opt-1.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__init__.cpython-314.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..5eb78e3 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__init__.cpython-314.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__main__.cpython-314.opt-1.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__main__.cpython-314.opt-1.pyc new file mode 100644 index 0000000..171da46 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__main__.cpython-314.opt-1.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__main__.cpython-314.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__main__.cpython-314.pyc new file mode 100644 index 0000000..171da46 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/__pycache__/__main__.cpython-314.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/frappe/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/frappe/dark.txt new file mode 100644 index 0000000..43d2d5d --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/frappe/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 6674ac +secondary_paletteKeyColor 71768e +tertiary_paletteKeyColor 9a6593 +neutral_paletteKeyColor 77767b +neutral_variant_paletteKeyColor 757680 +background 131317 +onBackground e4e1e7 +surface 131317 +surfaceDim 131317 +surfaceBright 39393d +surfaceContainerLowest 0d0e12 +surfaceContainerLow 1b1b1f +surfaceContainer 1f1f23 +surfaceContainerHigh 292a2e +surfaceContainerHighest 343438 +onSurface e4e1e7 +surfaceVariant 45464f +onSurfaceVariant c6c5d1 +inverseSurface e4e1e7 +inverseOnSurface 303034 +outline 8f909a +outlineVariant 45464f +shadow 000000 +scrim 000000 +surfaceTint b7c4ff +primary b7c4ff +onPrimary 1e2d60 +primaryContainer 6674ac +onPrimaryContainer ffffff +inversePrimary 4e5c92 +secondary c1c5e0 +onSecondary 2a2f44 +secondaryContainer 41465c +onSecondaryContainer afb4ce +tertiary f1b3e6 +onTertiary 4c1f49 +tertiaryContainer b67fae +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed dce1ff +primaryFixedDim b7c4ff +onPrimaryFixed 05164b +onPrimaryFixedVariant 364478 +secondaryFixed dde1fd +secondaryFixedDim c1c5e0 +onSecondaryFixed 151b2e +onSecondaryFixedVariant 41465c +tertiaryFixed ffd7f5 +tertiaryFixedDim f1b3e6 +onTertiaryFixed 330832 +onTertiaryFixedVariant 653661 +term0 353434 +term1 9a7bff +term2 44def5 +term3 ffdcf2 +term4 92acd6 +term5 a9a2ed +term6 9dceff +term7 e8d3de +term8 ac9fa9 +term9 b299ff +term10 89ecff +term11 fff0f6 +term12 b1c2db +term13 c1b7f7 +term14 bae0ff +term15 ffffff +rosewater f5eff9 +flamingo e5def4 +pink dcd9ff +mauve b5bbff +red b5a9ff +maroon c1b7ef +peach e0c2f9 +yellow ffecf3 +green c8e3ff +teal cee1ff +sky cadcff +sapphire aec7ff +blue a6baff +lavender bfcaff +klink 6685d1 +klinkSelection 6585d1 +kvisited 7276dd +kvisitedSelection 7276dd +knegative 8e70ff +knegativeSelection 8e70ff +kneutral c794ff +kneutralSelection c794ff +kpositive 54afff +kpositiveSelection 54afff +text e4e1e7 +subtext1 c6c5d1 +subtext0 8f909a +overlay2 7d7d86 +overlay1 6a6a72 +overlay0 585960 +surface2 48484e +surface1 37373d +surface0 25252a +base 131317 +mantle 131317 +crust 121216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/latte/light.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/latte/light.txt new file mode 100644 index 0000000..87b7353 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/latte/light.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 417da2 +secondary_paletteKeyColor 657a8a +tertiary_paletteKeyColor 92689d +neutral_paletteKeyColor 75777a +neutral_variant_paletteKeyColor 71787f +background f8f9fc +onBackground 191c1e +surface f8f9fc +surfaceDim d9dadd +surfaceBright f8f9fc +surfaceContainerLowest ffffff +surfaceContainerLow f2f3f7 +surfaceContainer edeef1 +surfaceContainerHigh e7e8eb +surfaceContainerHighest e1e2e6 +onSurface 191c1e +surfaceVariant dce3eb +onSurfaceVariant 41484e +inverseSurface 2e3133 +inverseOnSurface eff1f4 +outline 6e757c +outlineVariant c0c7ce +shadow 000000 +scrim 000000 +surfaceTint 236488 +primary 3e7b9f +onPrimary ffffff +primaryContainer 417da2 +onPrimaryContainer 00060c +inversePrimary 93cdf6 +secondary 4c6170 +onSecondary ffffff +secondaryContainer cfe5f8 +onSecondaryContainer 526776 +tertiary 8f659a +onTertiary ffffff +tertiaryContainer 8f659a +onTertiaryContainer ffffff +error ba1a1a +onError ffffff +errorContainer ffdad6 +onErrorContainer 93000a +primaryFixed c7e7ff +primaryFixedDim 93cdf6 +onPrimaryFixed 001e2e +onPrimaryFixedVariant 004c6d +secondaryFixed cfe5f8 +secondaryFixedDim b4c9db +onSecondaryFixed 071e2b +onSecondaryFixedVariant 354958 +tertiaryFixed fad7ff +tertiaryFixedDim e6b6f1 +onTertiaryFixed 2e0a3b +onTertiaryFixedVariant 5e3869 +term0 9a9b9b +term1 005bcc +term2 008ca5 +term3 7e61b0 +term4 009993 +term5 006ac4 +term6 3389ae +term7 202225 +term8 0f0f0f +term9 0071fa +term10 00afce +term11 9a7cce +term12 3fbdb6 +term13 1e85ec +term14 59a9d1 +term15 27282b +rosewater 7d76b1 +flamingo 6470bd +pink 057ee6 +mauve 005791 +red 003ee0 +maroon 2751f9 +peach 8a4dff +yellow 008f68 +green 007991 +teal 007195 +sky 0082b6 +sapphire 037ba6 +blue 005e90 +lavender 0077b7 +klink 2e8fc3 +klinkSelection 308fc4 +kvisited 2584d6 +kvisitedSelection 2984d7 +knegative 607eff +knegativeSelection 607eff +kneutral c794ff +kneutralSelection c794ff +kpositive 00b8de +kpositiveSelection 00b8df +text 191c1e +subtext1 41484e +subtext0 6e757c +overlay2 7f858b +overlay1 91979d +overlay0 a4a8ae +surface2 b7babf +surface1 cbced2 +surface0 e1e3e7 +base f8f9fc +mantle eff1f4 +crust e9ebef +success 4F6354 +onSuccess FFFFFF +successContainer D1E8D5 +onSuccessContainer 0C1F13 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/macchiato/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/macchiato/dark.txt new file mode 100644 index 0000000..cdc64d3 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/macchiato/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 6a73ac +secondary_paletteKeyColor 72758e +tertiary_paletteKeyColor 9b6592 +neutral_paletteKeyColor 77767b +neutral_variant_paletteKeyColor 767680 +background 131317 +onBackground e4e1e7 +surface 131317 +surfaceDim 131317 +surfaceBright 39393d +surfaceContainerLowest 0e0e12 +surfaceContainerLow 1b1b1f +surfaceContainer 1f1f23 +surfaceContainerHigh 2a2a2e +surfaceContainerHighest 353438 +onSurface e4e1e7 +surfaceVariant 46464f +onSurfaceVariant c6c5d1 +inverseSurface e4e1e7 +inverseOnSurface 303034 +outline 90909a +outlineVariant 46464f +shadow 000000 +scrim 000000 +surfaceTint bac3ff +primary bac3ff +onPrimary 232c60 +primaryContainer 6a73ac +onPrimaryContainer ffffff +inversePrimary 525b92 +secondary c3c5e0 +onSecondary 2c2f44 +secondaryContainer 42455c +onSecondaryContainer b1b3ce +tertiary f1b3e5 +onTertiary 4c1f48 +tertiaryContainer b77ead +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed dee0ff +primaryFixedDim bac3ff +onPrimaryFixed 0b154b +onPrimaryFixedVariant 3a4378 +secondaryFixed dfe1fd +secondaryFixedDim c3c5e0 +onSecondaryFixed 171a2e +onSecondaryFixedVariant 42455c +tertiaryFixed ffd7f4 +tertiaryFixedDim f1b3e5 +onTertiaryFixed 340831 +onTertiaryFixedVariant 66365f +term0 353434 +term1 a178ff +term2 44def5 +term3 ffdcf2 +term4 94abd7 +term5 ada0ed +term6 9dceff +term7 e8d3de +term8 ac9fa9 +term9 b797ff +term10 89ecff +term11 fff0f6 +term12 b2c2dc +term13 c4b6f6 +term14 bae0ff +term15 ffffff +rosewater f6eff9 +flamingo e7def4 +pink ded8ff +mauve b9baff +red b9a8ff +maroon c4b7ee +peach e0c2f9 +yellow ffecf3 +green c8e3ff +teal d0e0ff +sky ccdbff +sapphire b1c6ff +blue aab9ff +lavender c2c9ff +klink 6a84d1 +klinkSelection 6a84d1 +kvisited 7775dc +kvisitedSelection 7775dc +knegative 946dff +knegativeSelection 946dff +kneutral c794ff +kneutralSelection c794ff +kpositive 5daeff +kpositiveSelection 5eaeff +text e4e1e7 +subtext1 c6c5d1 +subtext0 90909a +overlay2 7d7d86 +overlay1 6a6a72 +overlay0 595960 +surface2 48484e +surface1 37373d +surface0 25252a +base 131317 +mantle 131317 +crust 121216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/mocha/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/mocha/dark.txt new file mode 100644 index 0000000..089a739 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/catppuccin/mocha/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 7171ac +secondary_paletteKeyColor 76758e +tertiary_paletteKeyColor 9e648e +neutral_paletteKeyColor 78767b +neutral_variant_paletteKeyColor 777680 +background 131317 +onBackground e5e1e7 +surface 131317 +surfaceDim 131317 +surfaceBright 39393d +surfaceContainerLowest 0e0e12 +surfaceContainerLow 1c1b1f +surfaceContainer 201f23 +surfaceContainerHigh 2a292e +surfaceContainerHighest 353438 +onSurface e5e1e7 +surfaceVariant 47464f +onSurfaceVariant c8c5d1 +inverseSurface e5e1e7 +inverseOnSurface 313034 +outline 918f9a +outlineVariant 47464f +shadow 000000 +scrim 000000 +surfaceTint c2c1ff +primary c2c1ff +onPrimary 2a2a60 +primaryContainer 7171ac +onPrimaryContainer ffffff +inversePrimary 595992 +secondary c6c4e0 +onSecondary 2e2e44 +secondaryContainer 45455c +onSecondaryContainer b4b2ce +tertiary f5b2e0 +onTertiary 4e1e44 +tertiaryContainer bb7da9 +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed e2dfff +primaryFixedDim c2c1ff +onPrimaryFixed 14134a +onPrimaryFixedVariant 414178 +secondaryFixed e2e0fd +secondaryFixedDim c6c4e0 +onSecondaryFixed 19192e +onSecondaryFixedVariant 45455c +tertiaryFixed ffd7f0 +tertiaryFixedDim f5b2e0 +onTertiaryFixed 35082e +onTertiaryFixedVariant 68355c +term0 353434 +term1 ac73ff +term2 44def5 +term3 ffdcf2 +term4 99aad8 +term5 b49fea +term6 9dceff +term7 e8d3de +term8 ac9fa9 +term9 c093ff +term10 89ecff +term11 fff0f6 +term12 b5c1dd +term13 c9b5f4 +term14 bae0ff +term15 ffffff +rosewater f7eff9 +flamingo e9def3 +pink e2d7ff +mauve bfb8ff +red c1a5fd +maroon c9b5ed +peach e0c2f9 +yellow ffecf3 +green c8e3ff +teal d3dfff +sky d0daff +sapphire b7c5ff +blue b0b8ff +lavender c7c8ff +klink 7382d2 +klinkSelection 7382d2 +kvisited 8172da +kvisitedSelection 8172da +knegative a167ff +knegativeSelection a167ff +kneutral ca92ff +kneutralSelection c992ff +kpositive 60adff +kpositiveSelection 60adff +text e5e1e7 +subtext1 c8c5d1 +subtext0 918f9a +overlay2 7e7c86 +overlay1 6b6972 +overlay0 595860 +surface2 48474e +surface1 37373d +surface0 25252a +base 131317 +mantle 131317 +crust 121216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/darkgreen/hard/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/darkgreen/hard/dark.txt new file mode 100644 index 0000000..dea54c4 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/darkgreen/hard/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 33653E +secondary_paletteKeyColor 1B4E2A +tertiary_paletteKeyColor 376942 +neutral_paletteKeyColor 1E1E26 +neutral_variant_paletteKeyColor 23252D +background 23262D +onBackground F5F5F6 +surface 050505 +surfaceDim 1E1E24 +surfaceBright 1E1E24 +surfaceContainerLowest 0a0a0b +surfaceContainerLow 0a0a0b +surfaceContainer 0a0a0b +surfaceContainerHigh 050505 +surfaceContainerHighest 0f1210 +onSurface F5F5F6 +surfaceVariant 0a0a0b +onSurfaceVariant c9c9c9 +inverseSurface 0a0a0b +inverseOnSurface ACACAC +outline 838383 +outlineVariant 1E1E25 +shadow 000000 +scrim 000000 +surfaceTint 24BD5C +primary 24BD5C +onPrimary 091f11 +primaryContainer 0f1210 +onPrimaryContainer 24BD5C +inversePrimary 24BD5C +secondary 24BD5C +onSecondary 043a14 +secondaryContainer 0f1210 +onSecondaryContainer F4F3F5 +tertiary 32653E +onTertiary F5F4F6 +tertiaryContainer 1E1E25 +onTertiaryContainer F5F5F6 +error c66e73 +onError F5F4F6 +errorContainer 893034 +onErrorContainer F5F4F6 +primaryFixed 24BD5C +primaryFixedDim 24BD5C +onPrimaryFixed F5F4F6 +onPrimaryFixedVariant F5F4F6 +secondaryFixed 24BD5C +secondaryFixedDim 24BD5C +onSecondaryFixed F5F4F6 +onSecondaryFixedVariant F5F4F6 +tertiaryFixed 24BD5C +tertiaryFixedDim 24BD5C +onTertiaryFixed F5F4F6 +onTertiaryFixedVariant F5F4F6 +term0 343434 +term1 23B65A +term2 43ff88 +term3 7cfcab +term4 78c19f +term5 7ae9a7 +term6 80deb2 +term7 ccdcd6 +term8 9aa59f +term9 cdff9e +term10 00f608 +term11 c9fff3 +term12 a4c7cd +term13 a5f7a2 +term14 87f1b5 +term15 ffffff +rosewater f4f0fa +flamingo dfe0f5 +pink bdffd4 +mauve 73fa90 +red 8affab +maroon abf0c5 +peach a9daac +yellow d0f9f4 +green 8af797 +teal a0f9aa +sky cefb97 +sapphire 85ef77 +blue 65eea0 +lavender 90f79e +klink 65eea0 +klinkSelection 65eea0 +kvisited 73fa90 +kvisitedSelection 73fa90 +knegative 8affab +knegativeSelection 8affab +kneutral d0f9f4 +kneutralSelection d0f9f4 +kpositive 8af797 +kpositiveSelection 8af797 +text e0e3e4 +subtext1 bec8cc +subtext0 889296 +overlay2 767f83 +overlay1 646c6f +overlay0 535a5d +surface2 43494b +surface1 33383a +surface0 212627 +base 101415 +mantle 101415 +crust 0f1314 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/darkgreen/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/darkgreen/medium/dark.txt new file mode 100644 index 0000000..1caff9e --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/darkgreen/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 33653E +secondary_paletteKeyColor 1B4E2A +tertiary_paletteKeyColor 376942 +neutral_paletteKeyColor 1E1E26 +neutral_variant_paletteKeyColor 23252D +background 23262D +onBackground F5F5F6 +surface 1E1E24 +surfaceDim 1E1E24 +surfaceBright 1E1E24 +surfaceContainerLowest 23262C +surfaceContainerLow 23262C +surfaceContainer 23262C +surfaceContainerHigh 1b1d22 +surfaceContainerHighest 232C29 +onSurface F5F5F6 +surfaceVariant 23262C +onSurfaceVariant c9c9c9 +inverseSurface 23262C +inverseOnSurface ACACAC +outline 979797 +outlineVariant 1E1E25 +shadow 000000 +scrim 000000 +surfaceTint 24BD5C +primary 24BD5C +onPrimary 091f11 +primaryContainer 232c29 +onPrimaryContainer 24BD5C +inversePrimary 24BD5C +secondary 24BD5C +onSecondary 043a14 +secondaryContainer 232c29 +onSecondaryContainer F4F3F5 +tertiary 32653E +onTertiary F5F4F6 +tertiaryContainer 1E1E25 +onTertiaryContainer F5F5F6 +error c66e73 +onError F5F4F6 +errorContainer 893034 +onErrorContainer F5F4F6 +primaryFixed 24BD5C +primaryFixedDim 24BD5C +onPrimaryFixed F5F4F6 +onPrimaryFixedVariant F5F4F6 +secondaryFixed 24BD5C +secondaryFixedDim 24BD5C +onSecondaryFixed F5F4F6 +onSecondaryFixedVariant F5F4F6 +tertiaryFixed 24BD5C +tertiaryFixedDim 24BD5C +onTertiaryFixed F5F4F6 +onTertiaryFixedVariant F5F4F6 +term0 343434 +term1 23B65A +term2 43ff88 +term3 7cfcab +term4 78c19f +term5 7ae9a7 +term6 80deb2 +term7 ccdcd6 +term8 9aa59f +term9 cdff9e +term10 00f608 +term11 c9fff3 +term12 a4c7cd +term13 a5f7a2 +term14 87f1b5 +term15 ffffff +rosewater f4f0fa +flamingo dfe0f5 +pink bdffd4 +mauve 73fa90 +red 8affab +maroon abf0c5 +peach a9daac +yellow d0f9f4 +green 8af797 +teal a0f9aa +sky cefb97 +sapphire 85ef77 +blue 65eea0 +lavender 90f79e +klink 65eea0 +klinkSelection 65eea0 +kvisited 73fa90 +kvisitedSelection 73fa90 +knegative 8affab +knegativeSelection 8affab +kneutral d0f9f4 +kneutralSelection d0f9f4 +kpositive 8af797 +kpositiveSelection 8af797 +text e0e3e4 +subtext1 bec8cc +subtext0 889296 +overlay2 767f83 +overlay1 646c6f +overlay0 535a5d +surface2 43494b +surface1 33383a +surface0 212627 +base 101415 +mantle 101415 +crust 0f1314 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/dracula/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/dracula/medium/dark.txt new file mode 100644 index 0000000..4195f45 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/dracula/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor BD93F9 +secondary_paletteKeyColor 50FA7B +tertiary_paletteKeyColor FF79C6 +neutral_paletteKeyColor 282A36 +neutral_variant_paletteKeyColor 44475A +background 282A36 +onBackground F8F8F2 +surface 343746 +surfaceDim 21222C +surfaceBright 4D4F66 +surfaceContainerLowest 191A21 +surfaceContainerLow 3C3F4E +surfaceContainer 3E4153 +surfaceContainerHigh 4D4F66 +surfaceContainerHighest 565970 +onSurface F8F8F2 +surfaceVariant 3E4153 +onSurfaceVariant F8F8F2 +inverseSurface F8F8F2 +inverseOnSurface 282A36 +outline 6272A4 +outlineVariant 4D4F66 +shadow 000000 +scrim 000000 +surfaceTint BD93F9 +primary BD93F9 +onPrimary 282A36 +primaryContainer 4D4F66 +onPrimaryContainer BD93F9 +inversePrimary 9D73D9 +secondary 50FA7B +onSecondary 282A36 +secondaryContainer 4D4F66 +onSecondaryContainer 50FA7B +tertiary FF79C6 +onTertiary 282A36 +tertiaryContainer 4D4F66 +onTertiaryContainer FF79C6 +error FF5555 +onError 282A36 +errorContainer 4C3743 +onErrorContainer FF5555 +primaryFixed BD93F9 +primaryFixedDim 9D73D9 +onPrimaryFixed 282A36 +onPrimaryFixedVariant 3E4153 +secondaryFixed 50FA7B +secondaryFixedDim 30DA5B +onSecondaryFixed 282A36 +onSecondaryFixedVariant 3E4153 +tertiaryFixed FF79C6 +tertiaryFixedDim DF59A6 +onTertiaryFixed 282A36 +onTertiaryFixedVariant 3E4153 +term0 282A36 +term1 FF5555 +term2 50FA7B +term3 F1FA8C +term4 BD93F9 +term5 FF79C6 +term6 8BE9FD +term7 F8F8F2 +term8 6272A4 +term9 FF6E6E +term10 69FF94 +term11 FFFFA5 +term12 D6ACFF +term13 FF92DF +term14 A4FFFF +term15 FFFFFF +rosewater F8F8F2 +flamingo FFB86C +pink FF79C6 +mauve BD93F9 +red FF5555 +maroon FF6E6E +peach FFB86C +yellow F1FA8C +green 50FA7B +teal 8BE9FD +sky 8BE9FD +sapphire 8BE9FD +blue BD93F9 +lavender BD93F9 +klink BD93F9 +klinkSelection BD93F9 +kvisited FF79C6 +kvisitedSelection FF79C6 +knegative FF5555 +knegativeSelection FF5555 +kneutral F1FA8C +kneutralSelection F1FA8C +kpositive 50FA7B +kpositiveSelection 50FA7B +text F8F8F2 +subtext1 F8F8F2 +subtext0 E6E6E6 +overlay2 A0A0A0 +overlay1 8A8A8A +overlay0 6272A4 +surface2 3E4153 +surface1 343746 +surface0 282A36 +base 282A36 +mantle 21222C +crust 191A21 +success 50FA7B +onSuccess 282A36 +successContainer 4D4F66 +onSuccessContainer F8F8F2 diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everblush/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everblush/medium/dark.txt new file mode 100644 index 0000000..fefd5ac --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everblush/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 8CCFB0 +secondary_paletteKeyColor E5C76B +tertiary_paletteKeyColor E5A5C5 +neutral_paletteKeyColor 2D3139 +neutral_variant_paletteKeyColor 3A3F4B +background 141B1E +onBackground E8E8E8 +surface 232A2D +surfaceDim 0F1416 +surfaceBright 3A4145 +surfaceContainerLowest 0A0E10 +surfaceContainerLow 2A3235 +surfaceContainer 2E3538 +surfaceContainerHigh 3A4145 +surfaceContainerHighest 434A4E +onSurface E8E8E8 +surfaceVariant 2E3538 +onSurfaceVariant B3B9BE +inverseSurface E8E8E8 +inverseOnSurface 141B1E +outline 8A8F94 +outlineVariant 3A4145 +shadow 000000 +scrim 000000 +surfaceTint 8CCFB0 +primary 8CCFB0 +onPrimary 141B1E +primaryContainer 3A4145 +onPrimaryContainer 8CCFB0 +inversePrimary 6FA98C +secondary E5C76B +onSecondary 141B1E +secondaryContainer 3A4145 +onSecondaryContainer E5C76B +tertiary E5A5C5 +onTertiary 141B1E +tertiaryContainer 3A4145 +onTertiaryContainer E5A5C5 +error E57474 +onError 141B1E +errorContainer 4A2C2C +onErrorContainer E57474 +primaryFixed 8CCFB0 +primaryFixedDim 6FA98C +onPrimaryFixed 141B1E +onPrimaryFixedVariant 3A3F4B +secondaryFixed E5C76B +secondaryFixedDim C4A855 +onSecondaryFixed 141B1E +onSecondaryFixedVariant 3A3F4B +tertiaryFixed E5A5C5 +tertiaryFixedDim C888A4 +onTertiaryFixed 141B1E +onTertiaryFixedVariant 3A3F4B +term0 141B1E +term1 E57474 +term2 8CCFB0 +term3 E5C76B +term4 67B0E8 +term5 C47FD5 +term6 6CBFBF +term7 E8E8E8 +term8 8A8F94 +term9 E57474 +term10 8CCFB0 +term11 E5C76B +term12 67B0E8 +term13 C47FD5 +term14 6CBFBF +term15 E8E8E8 +rosewater E8E8E8 +flamingo E5A5C5 +pink E5A5C5 +mauve C47FD5 +red E57474 +maroon E57474 +peach E59A84 +yellow E5C76B +green 8CCFB0 +teal 6CBFBF +sky 67B0E8 +sapphire 67B0E8 +blue 67B0E8 +lavender 67B0E8 +klink 67B0E8 +klinkSelection 67B0E8 +kvisited C47FD5 +kvisitedSelection C47FD5 +knegative E57474 +knegativeSelection E57474 +kneutral E5C76B +kneutralSelection E5C76B +kpositive 8CCFB0 +kpositiveSelection 8CCFB0 +text E8E8E8 +subtext1 B3B9BE +subtext0 8A8F94 +overlay2 7A7F84 +overlay1 6A6F74 +overlay0 5A5F64 +surface2 2E3538 +surface1 232A2D +surface0 1A2023 +base 141B1E +mantle 0F1416 +crust 0A0E10 +success 8CCFB0 +onSuccess 141B1E +successContainer 3A4145 +onSuccessContainer E8E8E8 diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/hard/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/hard/dark.txt new file mode 100644 index 0000000..d482350 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/hard/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 7FBBB3 +secondary_paletteKeyColor 83C092 +tertiary_paletteKeyColor A7C080 +neutral_paletteKeyColor 2E383C +neutral_variant_paletteKeyColor 374145 +background 1E2326 +onBackground D3C6AA +surface 252B2E +surfaceDim 15191C +surfaceBright 343E43 +surfaceContainerLowest 11161A +surfaceContainerLow 2A3338 +surfaceContainer 2E383C +surfaceContainerHigh 343E43 +surfaceContainerHighest 3A4448 +onSurface D3C6AA +surfaceVariant 374145 +onSurfaceVariant 9DA9A0 +inverseSurface D3C6AA +inverseOnSurface 1E2326 +outline 859289 +outlineVariant 414B50 +shadow 000000 +scrim 000000 +surfaceTint 7FBBB3 +primary 7FBBB3 +onPrimary 1E2326 +primaryContainer 414B50 +onPrimaryContainer A7C080 +inversePrimary 5A9A8F +secondary 83C092 +onSecondary 1E2326 +secondaryContainer 414B50 +onSecondaryContainer A7C080 +tertiary A7C080 +onTertiary 1E2326 +tertiaryContainer 414B50 +onTertiaryContainer D3C6AA +error E67E80 +onError 1E2326 +errorContainer 4C3743 +onErrorContainer E67E80 +primaryFixed 7FBBB3 +primaryFixedDim 5A9A8F +onPrimaryFixed 1E2326 +onPrimaryFixedVariant 374145 +secondaryFixed 83C092 +secondaryFixedDim 5F8C6F +onSecondaryFixed 1E2326 +onSecondaryFixedVariant 374145 +tertiaryFixed A7C080 +tertiaryFixedDim 7F9D5F +onTertiaryFixed 1E2326 +onTertiaryFixedVariant 374145 +term0 1E2326 +term1 E67E80 +term2 A7C080 +term3 DBBC7F +term4 7FBBB3 +term5 D699B6 +term6 83C092 +term7 D3C6AA +term8 859289 +term9 E67E80 +term10 A7C080 +term11 DBBC7F +term12 7FBBB3 +term13 D699B6 +term14 83C092 +term15 D3C6AA +rosewater D3C6AA +flamingo D699B6 +pink D699B6 +mauve D699B6 +red E67E80 +maroon E67E80 +peach E69875 +yellow DBBC7F +green A7C080 +teal 83C092 +sky 7FBBB3 +sapphire 7FBBB3 +blue 7FBBB3 +lavender 7FBBB3 +klink 7FBBB3 +klinkSelection 7FBBB3 +kvisited 83C092 +kvisitedSelection 83C092 +knegative E67E80 +knegativeSelection E67E80 +kneutral DBBC7F +kneutralSelection DBBC7F +kpositive A7C080 +kpositiveSelection A7C080 +text D3C6AA +subtext1 9DA9A0 +subtext0 859289 +overlay2 7A8478 +overlay1 6F7A6F +overlay0 5F6A5F +surface2 2E383C +surface1 252B2E +surface0 1E2326 +base 1E2326 +mantle 15191C +crust 11161A +success A7C080 +onSuccess 1E2326 +successContainer 414B50 +onSuccessContainer D3C6AA diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/medium/dark.txt new file mode 100644 index 0000000..8616743 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 7FBBB3 +secondary_paletteKeyColor 83C092 +tertiary_paletteKeyColor A7C080 +neutral_paletteKeyColor 2E383C +neutral_variant_paletteKeyColor 374145 +background 2D353B +onBackground D3C6AA +surface 343F44 +surfaceDim 232A2E +surfaceBright 475258 +surfaceContainerLowest 1E2326 +surfaceContainerLow 3B474E +surfaceContainer 3D484D +surfaceContainerHigh 475258 +surfaceContainerHighest 4C5258 +onSurface D3C6AA +surfaceVariant 3D484D +onSurfaceVariant 9DA9A0 +inverseSurface D3C6AA +inverseOnSurface 2D353B +outline 859289 +outlineVariant 475258 +shadow 000000 +scrim 000000 +surfaceTint 7FBBB3 +primary 7FBBB3 +onPrimary 2D353B +primaryContainer 475258 +onPrimaryContainer A7C080 +inversePrimary 5A9A8F +secondary 83C092 +onSecondary 2D353B +secondaryContainer 475258 +onSecondaryContainer A7C080 +tertiary A7C080 +onTertiary 2D353B +tertiaryContainer 475258 +onTertiaryContainer D3C6AA +error E67E80 +onError 2D353B +errorContainer 4C3743 +onErrorContainer E67E80 +primaryFixed 7FBBB3 +primaryFixedDim 5A9A8F +onPrimaryFixed 2D353B +onPrimaryFixedVariant 374145 +secondaryFixed 83C092 +secondaryFixedDim 5F8C6F +onSecondaryFixed 2D353B +onSecondaryFixedVariant 374145 +tertiaryFixed A7C080 +tertiaryFixedDim 7F9D5F +onTertiaryFixed 2D353B +onTertiaryFixedVariant 374145 +term0 2D353B +term1 E67E80 +term2 A7C080 +term3 DBBC7F +term4 7FBBB3 +term5 D699B6 +term6 83C092 +term7 D3C6AA +term8 859289 +term9 E67E80 +term10 A7C080 +term11 DBBC7F +term12 7FBBB3 +term13 D699B6 +term14 83C092 +term15 D3C6AA +rosewater D3C6AA +flamingo D699B6 +pink D699B6 +mauve D699B6 +red E67E80 +maroon E67E80 +peach E69875 +yellow DBBC7F +green A7C080 +teal 83C092 +sky 7FBBB3 +sapphire 7FBBB3 +blue 7FBBB3 +lavender 7FBBB3 +klink 7FBBB3 +klinkSelection 7FBBB3 +kvisited 83C092 +kvisitedSelection 83C092 +knegative E67E80 +knegativeSelection E67E80 +kneutral DBBC7F +kneutralSelection DBBC7F +kpositive A7C080 +kpositiveSelection A7C080 +text D3C6AA +subtext1 9DA9A0 +subtext0 859289 +overlay2 7A8478 +overlay1 6F7A6F +overlay0 5F6A5F +surface2 3D484D +surface1 343F44 +surface0 2D353B +base 2D353B +mantle 232A2E +crust 1E2326 +success A7C080 +onSuccess 2D353B +successContainer 475258 +onSuccessContainer D3C6AA diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/medium/light.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/medium/light.txt new file mode 100644 index 0000000..92fd1dc --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/medium/light.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 3A94C5 +secondary_paletteKeyColor 35A77C +tertiary_paletteKeyColor 8DA101 +neutral_paletteKeyColor E6E2CC +neutral_variant_paletteKeyColor E0DCC7 +background FDF6E3 +onBackground 5C6A72 +surface F3EAD3 +surfaceDim FDF6E3 +surfaceBright FFFBF0 +surfaceContainerLowest FFFBF0 +surfaceContainerLow FDF6E3 +surfaceContainer F3EAD3 +surfaceContainerHigh EAE4CA +surfaceContainerHighest E0DCC7 +onSurface 5C6A72 +surfaceVariant EAE4CA +onSurfaceVariant 6F7C84 +inverseSurface 5C6A72 +inverseOnSurface FDF6E3 +outline 939F91 +outlineVariant E0DCC7 +shadow 000000 +scrim 000000 +surfaceTint 3A94C5 +primary 3A94C5 +onPrimary FFFBF0 +primaryContainer E0DCC7 +onPrimaryContainer 8DA101 +inversePrimary 5FAFD7 +secondary 35A77C +onSecondary FFFBF0 +secondaryContainer E0DCC7 +onSecondaryContainer 8DA101 +tertiary 8DA101 +onTertiary FFFBF0 +tertiaryContainer E0DCC7 +onTertiaryContainer 5C6A72 +error F85552 +onError FFFBF0 +errorContainer E6E2CC +onErrorContainer F85552 +primaryFixed 3A94C5 +primaryFixedDim 5FAFD7 +onPrimaryFixed FFFBF0 +onPrimaryFixedVariant E0DCC7 +secondaryFixed 35A77C +secondaryFixedDim 5FC198 +onSecondaryFixed FFFBF0 +onSecondaryFixedVariant E0DCC7 +tertiaryFixed 8DA101 +tertiaryFixedDim A7C080 +onTertiaryFixed FFFBF0 +onTertiaryFixedVariant E0DCC7 +term0 5C6A72 +term1 F85552 +term2 8DA101 +term3 DFA000 +term4 3A94C5 +term5 DF69BA +term6 35A77C +term7 5C6A72 +term8 939F91 +term9 F85552 +term10 8DA101 +term11 DFA000 +term12 3A94C5 +term13 DF69BA +term14 35A77C +term15 5C6A72 +rosewater 5C6A72 +flamingo DF69BA +pink DF69BA +mauve DF69BA +red F85552 +maroon F85552 +peach E66868 +yellow DFA000 +green 8DA101 +teal 35A77C +sky 3A94C5 +sapphire 3A94C5 +blue 3A94C5 +lavender 3A94C5 +klink 3A94C5 +klinkSelection 3A94C5 +kvisited 35A77C +kvisitedSelection 35A77C +knegative F85552 +knegativeSelection F85552 +kneutral DFA000 +kneutralSelection DFA000 +kpositive 8DA101 +kpositiveSelection 8DA101 +text 5C6A72 +subtext1 6F7C84 +subtext0 939F91 +overlay2 A6B0A0 +overlay1 B9C0B0 +overlay0 CCD3C2 +surface2 EAE4CA +surface1 F3EAD3 +surface0 FDF6E3 +base FDF6E3 +mantle FFFBF0 +crust FFFEF9 +success 8DA101 +onSuccess FFFBF0 +successContainer E0DCC7 +onSuccessContainer 5C6A72 diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/soft/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/soft/dark.txt new file mode 100644 index 0000000..817425b --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/everforest/soft/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 7FBBB3 +secondary_paletteKeyColor 83C092 +tertiary_paletteKeyColor A7C080 +neutral_paletteKeyColor 2E383C +neutral_variant_paletteKeyColor 374145 +background 323C41 +onBackground D3C6AA +surface 3A454A +surfaceDim 282F34 +surfaceBright 4D585D +surfaceContainerLowest 232A2E +surfaceContainerLow 414D54 +surfaceContainer 434E53 +surfaceContainerHigh 4D585D +surfaceContainerHighest 525C61 +onSurface D3C6AA +surfaceVariant 434E53 +onSurfaceVariant 9DA9A0 +inverseSurface D3C6AA +inverseOnSurface 323C41 +outline 859289 +outlineVariant 4D585D +shadow 000000 +scrim 000000 +surfaceTint 7FBBB3 +primary 7FBBB3 +onPrimary 323C41 +primaryContainer 4D585D +onPrimaryContainer A7C080 +inversePrimary 5A9A8F +secondary 83C092 +onSecondary 323C41 +secondaryContainer 4D585D +onSecondaryContainer A7C080 +tertiary A7C080 +onTertiary 323C41 +tertiaryContainer 4D585D +onTertiaryContainer D3C6AA +error E67E80 +onError 323C41 +errorContainer 4C3743 +onErrorContainer E67E80 +primaryFixed 7FBBB3 +primaryFixedDim 5A9A8F +onPrimaryFixed 323C41 +onPrimaryFixedVariant 374145 +secondaryFixed 83C092 +secondaryFixedDim 5F8C6F +onSecondaryFixed 323C41 +onSecondaryFixedVariant 374145 +tertiaryFixed A7C080 +tertiaryFixedDim 7F9D5F +onTertiaryFixed 323C41 +onTertiaryFixedVariant 374145 +term0 323C41 +term1 E67E80 +term2 A7C080 +term3 DBBC7F +term4 7FBBB3 +term5 D699B6 +term6 83C092 +term7 D3C6AA +term8 859289 +term9 E67E80 +term10 A7C080 +term11 DBBC7F +term12 7FBBB3 +term13 D699B6 +term14 83C092 +term15 D3C6AA +rosewater D3C6AA +flamingo D699B6 +pink D699B6 +mauve D699B6 +red E67E80 +maroon E67E80 +peach E69875 +yellow DBBC7F +green A7C080 +teal 83C092 +sky 7FBBB3 +sapphire 7FBBB3 +blue 7FBBB3 +lavender 7FBBB3 +klink 7FBBB3 +klinkSelection 7FBBB3 +kvisited 83C092 +kvisitedSelection 83C092 +knegative E67E80 +knegativeSelection E67E80 +kneutral DBBC7F +kneutralSelection DBBC7F +kpositive A7C080 +kpositiveSelection A7C080 +text D3C6AA +subtext1 9DA9A0 +subtext0 859289 +overlay2 7A8478 +overlay1 6F7A6F +overlay0 5F6A5F +surface2 434E53 +surface1 3A454A +surface0 323C41 +base 323C41 +mantle 282F34 +crust 232A2E +success A7C080 +onSuccess 323C41 +successContainer 4D585D +onSuccessContainer D3C6AA diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/hard/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/hard/dark.txt new file mode 100644 index 0000000..4b63ec9 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/hard/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 2d8194 +secondary_paletteKeyColor 607b83 +tertiary_paletteKeyColor 8e69a1 +neutral_paletteKeyColor 747879 +neutral_variant_paletteKeyColor 6f797c +background 101415 +onBackground e0e3e4 +surface 101415 +surfaceDim 101415 +surfaceBright 363a3b +surfaceContainerLowest 0b0f10 +surfaceContainerLow 181c1d +surfaceContainer 1c2021 +surfaceContainerHigh 272b2c +surfaceContainerHighest 323537 +onSurface e0e3e4 +surfaceVariant 3f484b +onSurfaceVariant bec8cc +inverseSurface e0e3e4 +inverseOnSurface 2d3132 +outline 889296 +outlineVariant 3f484b +shadow 000000 +scrim 000000 +surfaceTint 85d2e7 +primary 85d2e7 +onPrimary 003640 +primaryContainer 2d8194 +onPrimaryContainer 000609 +inversePrimary 00687a +secondary aecbd4 +onSecondary 18343b +secondaryContainer 304b52 +onSecondaryContainer 9dbac3 +tertiary e1b7f5 +onTertiary 432255 +tertiaryContainer a982bc +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed acedff +primaryFixedDim 85d2e7 +onPrimaryFixed 001f26 +onPrimaryFixedVariant 004e5c +secondaryFixed cae7f1 +secondaryFixedDim aecbd4 +onSecondaryFixed 011f26 +onSecondaryFixedVariant 304b52 +tertiaryFixed f5d9ff +tertiaryFixedDim e1b7f5 +onTertiaryFixed 2c0b3f +onTertiaryFixedVariant 5b396d +term0 343434 +term1 8383ff +term2 40e1df +term3 75fcdd +term4 78b4c1 +term5 7aaee9 +term6 80d7de +term7 ccdcd6 +term8 9aa59f +term9 a29eff +term10 00f6f5 +term11 c9fff3 +term12 a4c7cd +term13 a2c0f7 +term14 87ebf1 +term15 ffffff +rosewater f4f0fa +flamingo dfe0f5 +pink bde1ff +mauve 73cafa +red 8ab5ff +maroon abbef0 +peach a9daac +yellow d0f9f4 +green 8af0f7 +teal a0ecf9 +sky 97e7fb +sapphire 77d4ef +blue 65c9ee +lavender 90d6f7 +klink 0093b4 +klinkSelection 0093b3 +kvisited 0089bf +kvisitedSelection 0089be +knegative 607eff +knegativeSelection 607eff +kneutral 34c359 +kneutralSelection 34c359 +kpositive 00bbc7 +kpositiveSelection 00bbc7 +text e0e3e4 +subtext1 bec8cc +subtext0 889296 +overlay2 767f83 +overlay1 646c6f +overlay0 535a5d +surface2 43494b +surface1 33383a +surface0 212627 +base 101415 +mantle 101415 +crust 0f1314 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/hard/light.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/hard/light.txt new file mode 100644 index 0000000..3ca8865 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/hard/light.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 7d7a2e +secondary_paletteKeyColor 7b7956 +tertiary_paletteKeyColor 57824d +neutral_paletteKeyColor 79776f +neutral_variant_paletteKeyColor 7a7868 +background fdf9ef +onBackground 1c1c16 +surface fdf9ef +surfaceDim dddad0 +surfaceBright fdf9ef +surfaceContainerLowest ffffff +surfaceContainerLow f7f3e9 +surfaceContainer f2eee4 +surfaceContainerHigh ece8de +surfaceContainerHighest e6e2d8 +onSurface 1c1c16 +surfaceVariant e7e3d0 +onSurfaceVariant 494739 +inverseSurface 32312a +inverseOnSurface f5f0e6 +outline 777565 +outlineVariant cac7b4 +shadow 000000 +scrim 000000 +surfaceTint 636116 +primary 636116 +onPrimary ffffff +primaryContainer 7a772c +onPrimaryContainer fffbff +inversePrimary ceca75 +secondary 62603e +onSecondary ffffff +secondaryContainer e8e4ba +onSecondaryContainer 686644 +tertiary 547f4a +onTertiary ffffff +tertiaryContainer 547f4a +onTertiaryContainer ffffff +error ba1a1a +onError ffffff +errorContainer ffdad6 +onErrorContainer 93000a +primaryFixed ebe68e +primaryFixedDim ceca75 +onPrimaryFixed 1e1d00 +onPrimaryFixedVariant 4b4900 +secondaryFixed e8e4ba +secondaryFixedDim ccc89f +onSecondaryFixed 1d1c03 +onSecondaryFixedVariant 4a4829 +tertiaryFixed bff0b0 +tertiaryFixedDim a4d396 +onTertiaryFixed 002201 +onTertiaryFixedVariant 275021 +term0 9d9a95 +term1 795d00 +term2 808606 +term3 846e00 +term4 948b22 +term5 8b6300 +term6 6e893e +term7 27211d +term8 0f0f0f +term9 967300 +term10 a1a62e +term11 a38918 +term12 b9ae43 +term13 ac7b00 +term14 8daa5b +term15 2e2723 +rosewater 937b2d +flamingo 917200 +pink a37500 +mauve 8f3b00 +red 695100 +maroon 7d6200 +peach 8c7400 +yellow 907e00 +green 6d7400 +teal 587027 +sky 4b882e +sapphire 5d7c2e +blue 00664e +lavender 00816c +klink 559652 +klinkSelection 559652 +kvisited c06b00 +kvisitedSelection c06b00 +knegative a78300 +knegativeSelection a78300 +kneutral c7a900 +kneutralSelection c7a900 +kpositive a0b31d +kpositiveSelection a1b31c +text 1c1c16 +subtext1 494739 +subtext0 777565 +overlay2 878576 +overlay1 999788 +overlay0 aba89a +surface2 bdbaad +surface1 d1cec2 +surface0 e7e3d8 +base fdf9ef +mantle f4f1e5 +crust efebdf +success 4F6354 +onSuccess FFFFFF +successContainer D1E8D5 +onSuccessContainer 0C1F13 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/medium/dark.txt new file mode 100644 index 0000000..65681fb --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 28828e +secondary_paletteKeyColor 5f7c81 +tertiary_paletteKeyColor 8a6aa3 +neutral_paletteKeyColor 747879 +neutral_variant_paletteKeyColor 6e797b +background 101415 +onBackground e0e3e4 +surface 101415 +surfaceDim 101415 +surfaceBright 363a3b +surfaceContainerLowest 0b0f10 +surfaceContainerLow 181c1d +surfaceContainer 1c2021 +surfaceContainerHigh 272b2b +surfaceContainerHighest 313536 +onSurface e0e3e4 +surfaceVariant 3e494a +onSurfaceVariant bec8ca +inverseSurface e0e3e4 +inverseOnSurface 2d3132 +outline 889394 +outlineVariant 3e494a +shadow 000000 +scrim 000000 +surfaceTint 81d3e0 +primary 81d3e0 +onPrimary 00363d +primaryContainer 28828e +onPrimaryContainer 000608 +inversePrimary 006874 +secondary adccd1 +onSecondary 173539 +secondaryContainer 2f4b50 +onSecondaryContainer 9cbac0 +tertiary ddb9f7 +onTertiary 402357 +tertiaryContainer a584bf +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed 9eeffd +primaryFixedDim 81d3e0 +onPrimaryFixed 001f24 +onPrimaryFixedVariant 004f57 +secondaryFixed c9e8ee +secondaryFixedDim adccd1 +onSecondaryFixed 001f24 +onSecondaryFixedVariant 2f4b50 +tertiaryFixed f2daff +tertiaryFixedDim ddb9f7 +onTertiaryFixed 290c41 +onTertiaryFixedVariant 573a6f +term0 343434 +term1 8383ff +term2 44e1d5 +term3 75fcdd +term4 76b4bd +term5 7aaee9 +term6 80d8d8 +term7 ccdcd6 +term8 9aa59f +term9 a29eff +term10 13f7ea +term11 c9fff3 +term12 a3c7ca +term13 a2c0f7 +term14 87ecea +term15 ffffff +rosewater f1f3e5 +flamingo dfe0f5 +pink bae2ff +mauve 6cccf4 +red 8ab5ff +maroon abbef0 +peach a9daac +yellow d1faf1 +green 8af0f0 +teal 9fecf4 +sky 94e8f6 +sapphire 74d5e9 +blue 5fcae8 +lavender 8cd7f3 +klink 0094ac +klinkSelection 0094ab +kvisited 008bb6 +kvisitedSelection 008bb5 +knegative 607eff +knegativeSelection 607eff +kneutral 34c359 +kneutralSelection 34c359 +kpositive 00bcbf +kpositiveSelection 00bcbd +text e0e3e4 +subtext1 bec8ca +subtext0 889394 +overlay2 768081 +overlay1 646c6e +overlay0 535b5c +surface2 434a4b +surface1 33383a +surface0 212627 +base 101415 +mantle 101415 +crust 0f1314 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/medium/light.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/medium/light.txt new file mode 100644 index 0000000..62a2878 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/medium/light.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 857829 +secondary_paletteKeyColor 7f7753 +tertiary_paletteKeyColor 5f8146 +neutral_paletteKeyColor 7a776f +neutral_variant_paletteKeyColor 7b7767 +background fef9ee +onBackground 1d1c15 +surface fef9ee +surfaceDim dfd9cf +surfaceBright fef9ee +surfaceContainerLowest ffffff +surfaceContainerLow f9f3e9 +surfaceContainer f3ede3 +surfaceContainerHigh ede8dd +surfaceContainerHighest e7e2d8 +onSurface 1d1c15 +surfaceVariant e9e2cf +onSurfaceVariant 4a4738 +inverseSurface 32302a +inverseOnSurface f6f0e6 +outline 797564 +outlineVariant ccc6b3 +shadow 000000 +scrim 000000 +surfaceTint 6b5f10 +primary 6b5f10 +onPrimary ffffff +primaryContainer 827526 +onPrimaryContainer fffbff +inversePrimary d7c76f +secondary 655f3c +onSecondary ffffff +secondaryContainer ede3b7 +onSecondaryContainer 6c6542 +tertiary 5c7e43 +onTertiary ffffff +tertiaryContainer 5c7e43 +onTertiaryContainer ffffff +error ba1a1a +onError ffffff +errorContainer ffdad6 +onErrorContainer 93000a +primaryFixed f4e388 +primaryFixedDim d7c76f +onPrimaryFixed 201c00 +onPrimaryFixedVariant 514700 +secondaryFixed ede3b7 +secondaryFixedDim d0c79d +onSecondaryFixed 201c02 +onSecondaryFixedVariant 4d4727 +tertiaryFixed c7eea8 +tertiaryFixedDim acd28e +onTertiaryFixed 0b2000 +onTertiaryFixedVariant 304f1a +term0 9d9a95 +term1 7e5a00 +term2 898300 +term3 8a6b00 +term4 9c881c +term5 8f6100 +term6 768737 +term7 27211d +term8 0f0f0e +term9 9c7000 +term10 aaa425 +term11 aa8616 +term12 c1ab3e +term13 b17900 +term14 96a854 +term15 2e2723 +rosewater 98792c +flamingo 976f00 +pink a87300 +mauve 8f3b00 +red 6d4f00 +maroon 836000 +peach 927100 +yellow 967b00 +green 757200 +teal 5f6f20 +sky 4b882e +sapphire 657b26 +blue 00664e +lavender 00816c +klink 559652 +klinkSelection 559652 +kvisited c06b00 +kvisitedSelection c06b00 +knegative ae8000 +knegativeSelection ae8000 +kneutral d1a500 +kneutralSelection d0a500 +kpositive adaf00 +kpositiveSelection adaf00 +text 1d1c15 +subtext1 4a4738 +subtext0 797564 +overlay2 898575 +overlay1 9b9787 +overlay0 ada899 +surface2 bfbaac +surface1 d2cec1 +surface0 e8e3d7 +base fef9ee +mantle f6f1e4 +crust f0ebde +success 4F6354 +onSuccess FFFFFF +successContainer D1E8D5 +onSuccessContainer 0C1F13 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/soft/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/soft/dark.txt new file mode 100644 index 0000000..8c69979 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/soft/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor a46a32 +secondary_paletteKeyColor 907156 +tertiary_paletteKeyColor 767c33 +neutral_paletteKeyColor 7e756f +neutral_variant_paletteKeyColor 847468 +background 18120e +onBackground ece0d9 +surface 18120e +surfaceDim 18120e +surfaceBright 3f3833 +surfaceContainerLowest 120d09 +surfaceContainerLow 201a16 +surfaceContainer 241e1a +surfaceContainerHigh 2f2924 +surfaceContainerHighest 3a332e +onSurface ece0d9 +surfaceVariant 52443a +onSurfaceVariant d6c3b5 +inverseSurface ece0d9 +inverseOnSurface 362f2a +outline 9f8e81 +outlineVariant 52443a +shadow 000000 +scrim 000000 +surfaceTint ffb878 +primary ffb878 +onPrimary 4c2700 +primaryContainer c28349 +onPrimaryContainer 0d0400 +inversePrimary 87521c +secondary e5bfa1 +onSecondary 432b16 +secondaryContainer 5c412a +onSecondaryContainer d3ae90 +tertiary c6cc7a +onTertiary 2f3300 +tertiaryContainer 90964a +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed ffdcc1 +primaryFixedDim ffb878 +onPrimaryFixed 2e1500 +onPrimaryFixedVariant 6b3b04 +secondaryFixed ffdcc1 +secondaryFixedDim e5bfa1 +onSecondaryFixed 2b1704 +onSecondaryFixedVariant 5c412a +tertiaryFixed e2e993 +tertiaryFixedDim c6cc7a +onTertiaryFixed 1b1d00 +onTertiaryFixedVariant 454a03 +term0 353433 +term1 e17300 +term2 ffc071 +term3 ffe0c6 +term4 b9ab66 +term5 ed9562 +term6 f4c16d +term7 ebd4c1 +term8 b29f91 +term9 ff8a20 +term10 ffd6a8 +term11 fff2e8 +term12 d7be91 +term13 fcad7e +term14 ffd497 +term15 ffffff +rosewater ffeee5 +flamingo fedbc7 +pink ffd4c1 +mauve ffac8e +red fe9c5e +maroon f5af83 +peach ffc18f +yellow ffeee1 +green ffdaa5 +teal ffdb92 +sky e1df87 +sapphire b3d27e +blue ffa2bd +lavender ffbcbb +klink bf6ba0 +klinkSelection bf6ba0 +kvisited cc6232 +kvisitedSelection cc6232 +knegative d66a00 +knegativeSelection d66900 +kneutral ff8d00 +kneutralSelection ff8d06 +kpositive de9d00 +kpositiveSelection df9d00 +text ece0d9 +subtext1 d6c3b5 +subtext0 9f8e81 +overlay2 8b7b70 +overlay1 76685e +overlay0 63574e +surface2 51463f +surface1 3f362f +surface0 2b241f +base 18120e +mantle 18120e +crust 17110d +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/soft/light.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/soft/light.txt new file mode 100644 index 0000000..e57eb7d --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/gruvbox/soft/light.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 887627 +secondary_paletteKeyColor 817753 +tertiary_paletteKeyColor 628043 +neutral_paletteKeyColor 7b776f +neutral_variant_paletteKeyColor 7d7766 +background fff9ee +onBackground 1d1b15 +surface fff9ee +surfaceDim dfd9cf +surfaceBright fff9ee +surfaceContainerLowest ffffff +surfaceContainerLow f9f3e8 +surfaceContainer f3ede3 +surfaceContainerHigh eee7dd +surfaceContainerHighest e8e2d8 +onSurface 1d1b15 +surfaceVariant eae2ce +onSurfaceVariant 4b4738 +inverseSurface 333029 +inverseOnSurface f6f0e6 +outline 7a7464 +outlineVariant cdc6b3 +shadow 000000 +scrim 000000 +surfaceTint 6e5d0e +primary 867425 +onPrimary ffffff +primaryContainer 887627 +onPrimaryContainer 070500 +inversePrimary dcc66e +secondary 675e3c +onSecondary ffffff +secondaryContainer efe2b7 +onSecondaryContainer 6d6441 +tertiary 5f7d41 +onTertiary ffffff +tertiaryContainer 5f7d41 +onTertiaryContainer ffffff +error ba1a1a +onError ffffff +errorContainer ffdad6 +onErrorContainer 93000a +primaryFixed f9e287 +primaryFixedDim dcc66e +onPrimaryFixed 221b00 +onPrimaryFixedVariant 544600 +secondaryFixed efe2b7 +secondaryFixedDim d3c69c +onSecondaryFixed 211b02 +onSecondaryFixedVariant 4f4726 +tertiaryFixed cbeea5 +tertiaryFixedDim b0d18b +onTertiaryFixed 0e2000 +onTertiaryFixedVariant 334e17 +term0 9e9a95 +term1 815900 +term2 8d8200 +term3 8d6a00 +term4 a0871a +term5 926000 +term6 7a8734 +term7 27211d +term8 0f0f0e +term9 9f6f00 +term10 afa220 +term11 ae8516 +term12 c5aa3c +term13 b47700 +term14 9aa751 +term15 2e2723 +rosewater 9b782c +flamingo 9a6e00 +pink ab7100 +mauve 8f3b00 +red 6f4e00 +maroon 855f00 +peach 957000 +yellow 9a7a00 +green 797100 +teal 636e1c +sky 4b882e +sapphire 6a7a22 +blue 00664e +lavender c2484e +klink 559652 +klinkSelection 559652 +kvisited c06b00 +kvisitedSelection c06b00 +knegative b27f00 +knegativeSelection b27f00 +kneutral d5a300 +kneutralSelection d5a300 +kpositive b3ae00 +kpositiveSelection b3ae00 +text 1d1b15 +subtext1 4b4738 +subtext0 7a7464 +overlay2 8a8475 +overlay1 9c9687 +overlay0 aea899 +surface2 c0baac +surface1 d3cdc0 +surface0 e9e3d7 +base fff9ee +mantle f7f1e4 +crust f1ebde +success 4F6354 +onSuccess FFFFFF +successContainer D1E8D5 +onSuccessContainer 0C1F13 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/nord/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/nord/medium/dark.txt new file mode 100644 index 0000000..9e0cc02 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/nord/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 88C0D0 +secondary_paletteKeyColor 81A1C1 +tertiary_paletteKeyColor 5E81AC +neutral_paletteKeyColor 3B4252 +neutral_variant_paletteKeyColor 434C5E +background 2E3440 +onBackground ECEFF4 +surface 3B4252 +surfaceDim 242933 +surfaceBright 4C566A +surfaceContainerLowest 1F232C +surfaceContainerLow 424A5E +surfaceContainer 434C5E +surfaceContainerHigh 4C566A +surfaceContainerHighest 55606E +onSurface ECEFF4 +surfaceVariant 434C5E +onSurfaceVariant D8DEE9 +inverseSurface ECEFF4 +inverseOnSurface 2E3440 +outline 616E88 +outlineVariant 4C566A +shadow 000000 +scrim 000000 +surfaceTint 88C0D0 +primary 88C0D0 +onPrimary 2E3440 +primaryContainer 4C566A +onPrimaryContainer 88C0D0 +inversePrimary 6FA3B3 +secondary 81A1C1 +onSecondary 2E3440 +secondaryContainer 4C566A +onSecondaryContainer 81A1C1 +tertiary 5E81AC +onTertiary 2E3440 +tertiaryContainer 4C566A +onTertiaryContainer 5E81AC +error BF616A +onError 2E3440 +errorContainer 4C3743 +onErrorContainer BF616A +primaryFixed 88C0D0 +primaryFixedDim 6FA3B3 +onPrimaryFixed 2E3440 +onPrimaryFixedVariant 434C5E +secondaryFixed 81A1C1 +secondaryFixedDim 6A84A4 +onSecondaryFixed 2E3440 +onSecondaryFixedVariant 434C5E +tertiaryFixed 5E81AC +tertiaryFixedDim 4A6A8F +onTertiaryFixed 2E3440 +onTertiaryFixedVariant 434C5E +term0 3B4252 +term1 BF616A +term2 A3BE8C +term3 EBCB8B +term4 81A1C1 +term5 B48EAD +term6 88C0D0 +term7 E5E9F0 +term8 4C566A +term9 BF616A +term10 A3BE8C +term11 EBCB8B +term12 81A1C1 +term13 B48EAD +term14 8FBCBB +term15 ECEFF4 +rosewater ECEFF4 +flamingo B48EAD +pink B48EAD +mauve B48EAD +red BF616A +maroon BF616A +peach D08770 +yellow EBCB8B +green A3BE8C +teal 8FBCBB +sky 88C0D0 +sapphire 81A1C1 +blue 5E81AC +lavender 5E81AC +klink 88C0D0 +klinkSelection 88C0D0 +kvisited 81A1C1 +kvisitedSelection 81A1C1 +knegative BF616A +knegativeSelection BF616A +kneutral EBCB8B +kneutralSelection EBCB8B +kpositive A3BE8C +kpositiveSelection A3BE8C +text ECEFF4 +subtext1 D8DEE9 +subtext0 616E88 +overlay2 5A677E +overlay1 4F5B73 +overlay0 434C5E +surface2 434C5E +surface1 3B4252 +surface0 2E3440 +base 2E3440 +mantle 242933 +crust 1F232C +success A3BE8C +onSuccess 2E3440 +successContainer 4C566A +onSuccessContainer ECEFF4 diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/oldworld/default/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/oldworld/default/dark.txt new file mode 100644 index 0000000..9059dfc --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/oldworld/default/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 5a77ab +secondary_paletteKeyColor 6d778e +tertiary_paletteKeyColor 966699 +neutral_paletteKeyColor 76777b +neutral_variant_paletteKeyColor 747780 +background 121317 +onBackground e3e2e7 +surface 121317 +surfaceDim 121317 +surfaceBright 38393d +surfaceContainerLowest 0d0e11 +surfaceContainerLow 1a1b1f +surfaceContainer 1e2023 +surfaceContainerHigh 292a2e +surfaceContainerHighest 343538 +onSurface e3e2e7 +surfaceVariant 43474f +onSurfaceVariant c4c6d0 +inverseSurface e3e2e7 +inverseOnSurface 2f3034 +outline 8e909a +outlineVariant 43474f +shadow 000000 +scrim 000000 +surfaceTint aac7ff +primary aac7ff +onPrimary 0b3060 +primaryContainer 5a77ab +onPrimaryContainer ffffff +inversePrimary 415e91 +secondary bcc7df +onSecondary 263144 +secondaryContainer 3d475b +onSecondaryContainer abb5ce +tertiary ecb4ed +onTertiary 49204e +tertiaryContainer b280b4 +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed d7e3ff +primaryFixedDim aac7ff +onPrimaryFixed 001b3e +onPrimaryFixedVariant 284777 +secondaryFixed d8e2fc +secondaryFixedDim bcc7df +onSecondaryFixed 111c2e +onSecondaryFixedVariant 3d475b +tertiaryFixed ffd6fd +tertiaryFixedDim ecb4ed +onTertiaryFixed 310938 +onTertiaryFixedVariant 623766 +term0 353434 +term1 8881ff +term2 44def5 +term3 ffdcf2 +term4 8badd4 +term5 9ea5ef +term6 95d0fb +term7 e8d3de +term8 ac9fa9 +term9 a39eff +term10 89ecff +term11 c9fff3 +term12 aec3da +term13 b7baf8 +term14 b7e0ff +term15 ffffff +rosewater f4f0fa +flamingo e2dff5 +pink d7dbff +mauve abbeff +red a9adff +maroon b9baf1 +peach e0c2f9 +yellow d0f9f4 +green c3e4ff +teal c8e2ff +sky c4ddff +sapphire a4caff +blue 9abdff +lavender b7ccff +klink 5689ce +klinkSelection 5689ce +kvisited 5f7bdd +kvisitedSelection 5f7bdd +knegative 7877ff +knegativeSelection 7878ff +kneutral c794ff +kneutralSelection c794ff +kpositive 13b3ff +kpositiveSelection 0db3ff +text e3e2e7 +subtext1 c4c6d0 +subtext0 8e909a +overlay2 7c7d86 +overlay1 686a72 +overlay0 575960 +surface2 46484e +surface1 36373d +surface0 24252a +base 121317 +mantle 121317 +crust 111216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/onedark/default/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/onedark/default/dark.txt new file mode 100644 index 0000000..f300198 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/onedark/default/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 5878ab +secondary_paletteKeyColor 6c778d +tertiary_paletteKeyColor 966799 +neutral_paletteKeyColor 76777b +neutral_variant_paletteKeyColor 747780 +background 121317 +onBackground e3e2e7 +surface 121317 +surfaceDim 121317 +surfaceBright 38393d +surfaceContainerLowest 0d0e11 +surfaceContainerLow 1a1c1f +surfaceContainer 1e2023 +surfaceContainerHigh 292a2d +surfaceContainerHighest 333538 +onSurface e3e2e7 +surfaceVariant 43474f +onSurfaceVariant c3c6d0 +inverseSurface e3e2e7 +inverseOnSurface 2f3034 +outline 8d919a +outlineVariant 43474f +shadow 000000 +scrim 000000 +surfaceTint a8c8ff +primary a8c8ff +onPrimary 05305f +primaryContainer 7292c6 +onPrimaryContainer 000513 +inversePrimary 3e5f90 +secondary bbc7df +onSecondary 253144 +secondaryContainer 3c475b +onSecondaryContainer aab5cd +tertiary ebb5ec +onTertiary 48204e +tertiaryContainer b180b4 +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed d5e3ff +primaryFixedDim a8c8ff +onPrimaryFixed 001b3c +onPrimaryFixedVariant 254777 +secondaryFixed d7e3fc +secondaryFixedDim bbc7df +onSecondaryFixed 101c2e +onSecondaryFixedVariant 3c475b +tertiaryFixed ffd6fe +tertiaryFixedDim ebb5ec +onTertiaryFixed 310937 +onTertiaryFixedVariant 613766 +term0 343434 +term1 8483ff +term2 44def5 +term3 ffdcf2 +term4 8aaed3 +term5 9ca5ef +term6 94d0fa +term7 e8d3de +term8 ac9fa9 +term9 a29eff +term10 89ecff +term11 c9fff3 +term12 adc4d9 +term13 b5baf8 +term14 b6e1ff +term15 ffffff +rosewater f4f0fa +flamingo e2e0f5 +pink d6dbff +mauve a9bfff +red a6aeff +maroon b7baf1 +peach e0c2f9 +yellow d0f9f4 +green c1e4ff +teal c7e3ff +sky c2deff +sapphire a1caff +blue 97beff +lavender b5cdff +klink 5389ce +klinkSelection 5489ce +kvisited 5b7cdd +kvisitedSelection 5c7bdd +knegative 7479ff +knegativeSelection 7578ff +kneutral c794ff +kneutralSelection c794ff +kpositive 00b4fd +kpositiveSelection 00b4fe +text e3e2e7 +subtext1 c3c6d0 +subtext0 8d919a +overlay2 7b7e86 +overlay1 686b72 +overlay0 575960 +surface2 46484e +surface1 36373d +surface0 24252a +base 121317 +mantle 121317 +crust 111216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/dawn/light.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/dawn/light.txt new file mode 100644 index 0000000..d564a5d --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/dawn/light.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 8b7526 +secondary_paletteKeyColor 827652 +tertiary_paletteKeyColor 667f40 +neutral_paletteKeyColor 7b776f +neutral_variant_paletteKeyColor 7e7766 +background fff8f0 +onBackground 1e1b15 +surface fff8f0 +surfaceDim e0d9cf +surfaceBright fff8f0 +surfaceContainerLowest ffffff +surfaceContainerLow faf3e8 +surfaceContainer f4ede3 +surfaceContainerHigh eee7dd +surfaceContainerHighest e8e2d7 +onSurface 1e1b15 +surfaceVariant ebe2ce +onSurfaceVariant 4c4638 +inverseSurface 333029 +inverseOnSurface f7f0e5 +outline 7b7464 +outlineVariant cec6b3 +shadow 000000 +scrim 000000 +surfaceTint 715c0d +primary 897324 +onPrimary ffffff +primaryContainer 8b7526 +onPrimaryContainer 070500 +inversePrimary e0c56d +secondary 695e3b +onSecondary ffffff +secondaryContainer f1e2b6 +onSecondaryContainer 6f6441 +tertiary 647d3e +onTertiary ffffff +tertiaryContainer 647d3e +onTertiaryContainer ffffff +error ba1a1a +onError ffffff +errorContainer ffdad6 +onErrorContainer 93000a +primaryFixed fde186 +primaryFixedDim e0c56d +onPrimaryFixed 231b00 +onPrimaryFixedVariant 564500 +secondaryFixed f1e2b6 +secondaryFixedDim d5c69c +onSecondaryFixed 221b02 +onSecondaryFixedVariant 504626 +tertiaryFixed d0eda2 +tertiaryFixedDim b4d088 +onTertiaryFixed 121f00 +onTertiaryFixedVariant 374d14 +term0 9e9a95 +term1 835800 +term2 908100 +term3 906900 +term4 a38618 +term5 945e00 +term6 7d8631 +term7 27211d +term8 100f0e +term9 a26e00 +term10 b3a11d +term11 b08416 +term12 c8a93b +term13 b77600 +term14 9da74e +term15 2e2723 +rosewater 9d772d +flamingo 9c6d00 +pink ae7000 +mauve 8f3b00 +red 714d00 +maroon 885e00 +peach 986f00 +yellow 9d7900 +green 7b7000 +teal 666d19 +sky 4b882e +sapphire 6d791e +blue 00664e +lavender c2484e +klink 559652 +klinkSelection 559652 +kvisited c06b00 +kvisitedSelection c06b00 +knegative b47d00 +knegativeSelection b57d00 +kneutral d8a200 +kneutralSelection d9a200 +kpositive b7ac00 +kpositiveSelection b8ac00 +text 1e1b15 +subtext1 4c4638 +subtext0 7b7464 +overlay2 8b8475 +overlay1 9d9688 +overlay0 aea79a +surface2 c0b9ae +surface1 d4cdc2 +surface0 e9e2d9 +base fff8f0 +mantle f7f0e6 +crust f2eae0 +success 4F6354 +onSuccess FFFFFF +successContainer D1E8D5 +onSuccessContainer 0C1F13 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/main/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/main/dark.txt new file mode 100644 index 0000000..e5e5adb --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/main/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 786fab +secondary_paletteKeyColor 79748e +tertiary_paletteKeyColor a1638a +neutral_paletteKeyColor 79767b +neutral_variant_paletteKeyColor 787580 +background 141317 +onBackground e5e1e7 +surface 141317 +surfaceDim 141317 +surfaceBright 3a383d +surfaceContainerLowest 0e0e11 +surfaceContainerLow 1c1b1f +surfaceContainer 201f23 +surfaceContainerHigh 2b292e +surfaceContainerHighest 363438 +onSurface e5e1e7 +surfaceVariant 48454f +onSurfaceVariant c9c4d0 +inverseSurface e5e1e7 +inverseOnSurface 313034 +outline 938f9a +outlineVariant 48454f +shadow 000000 +scrim 000000 +surfaceTint c9bfff +primary c9bfff +onPrimary 31285f +primaryContainer 786fab +onPrimaryContainer ffffff +inversePrimary 5f5791 +secondary c9c3e0 +onSecondary 312e44 +secondaryContainer 48445b +onSecondaryContainer b7b1ce +tertiary f9b1dc +onTertiary 501d41 +tertiaryContainer be7ca5 +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed e5deff +primaryFixedDim c9bfff +onPrimaryFixed 1b1149 +onPrimaryFixedVariant 473f77 +secondaryFixed e5dffc +secondaryFixedDim c9c3e0 +onSecondaryFixed 1c192e +onSecondaryFixedVariant 48445b +tertiaryFixed ffd8ec +tertiaryFixedDim f9b1dc +onTertiaryFixed 37072b +onTertiaryFixedVariant 6a3458 +term0 353434 +term1 b96cff +term2 ffbac2 +term3 ffdcf2 +term4 9da8d8 +term5 bb9de8 +term6 9dceff +term7 e8d3de +term8 ac9fa9 +term9 cb8fff +term10 ffd2d5 +term11 fff0f6 +term12 b7c0dd +term13 cfb3f2 +term14 bae0ff +term15 ffffff +rosewater f8eff8 +flamingo ebddf2 +pink e6d6ff +mauve c6b6ff +red c9a3fa +maroon ceb4eb +peach e5c1f6 +yellow ffecf3 +green c8e3ff +teal d7dfff +sky d3d9ff +sapphire bdc3ff +blue b7b6ff +lavender ccc6ff +klink 7b80d1 +klinkSelection 7b80d1 +kvisited 8a6fd7 +kvisitedSelection 8a6fd7 +knegative ac62fa +knegativeSelection ac62fa +kneutral d48dff +kneutralSelection d48eff +kpositive 60adff +kpositiveSelection 60adff +text e5e1e7 +subtext1 c9c4d0 +subtext0 938f9a +overlay2 807c86 +overlay1 6c6972 +overlay0 5b5860 +surface2 4a474e +surface1 39373d +surface0 262529 +base 141317 +mantle 141317 +crust 131216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/moon/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/moon/dark.txt new file mode 100644 index 0000000..4686ac9 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/rosepine/moon/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 7670ac +secondary_paletteKeyColor 78748e +tertiary_paletteKeyColor a1638b +neutral_paletteKeyColor 78767b +neutral_variant_paletteKeyColor 787680 +background 141317 +onBackground e5e1e7 +surface 141317 +surfaceDim 141317 +surfaceBright 3a383d +surfaceContainerLowest 0e0e11 +surfaceContainerLow 1c1b1f +surfaceContainer 201f23 +surfaceContainerHigh 2a292e +surfaceContainerHighest 353438 +onSurface e5e1e7 +surfaceVariant 47454f +onSurfaceVariant c9c5d0 +inverseSurface e5e1e7 +inverseOnSurface 313034 +outline 928f9a +outlineVariant 47454f +shadow 000000 +scrim 000000 +surfaceTint c6bfff +primary c6bfff +onPrimary 2e2960 +primaryContainer 7670ac +onPrimaryContainer 040025 +inversePrimary 5d5791 +secondary c8c3e0 +onSecondary 302e44 +secondaryContainer 47445c +onSecondaryContainer b6b2ce +tertiary f9b1dd +onTertiary 501d41 +tertiaryContainer be7ca6 +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed e4dfff +primaryFixedDim c6bfff +onPrimaryFixed 19124a +onPrimaryFixedVariant 454078 +secondaryFixed e4dffd +secondaryFixedDim c8c3e0 +onSecondaryFixed 1b192e +onSecondaryFixedVariant 47445c +tertiaryFixed ffd8ed +tertiaryFixedDim f9b1dd +onTertiaryFixed 37072b +onTertiaryFixedVariant 6a3459 +term0 353434 +term1 b56eff +term2 ffbac2 +term3 ffdcf2 +term4 9ca9d8 +term5 b89de9 +term6 9dceff +term7 e8d3de +term8 ac9fa9 +term9 c791ff +term10 89ecff +term11 fff0f6 +term12 b7c0dd +term13 cdb4f3 +term14 bae0ff +term15 ffffff +rosewater f8eff8 +flamingo eaddf3 +pink e4d7ff +mauve c4b7ff +red c6a4fb +maroon ccb4eb +peach e4c1f7 +yellow ffecf3 +green c8e3ff +teal d5dfff +sky d2d9ff +sapphire bbc4ff +blue b5b6ff +lavender cbc7ff +klink 7880d1 +klinkSelection 7881d1 +kvisited 8770d8 +kvisitedSelection 8770d8 +knegative a964fd +knegativeSelection a864fd +kneutral d08fff +kneutralSelection d090ff +kpositive 60adff +kpositiveSelection 60adff +text e5e1e7 +subtext1 c9c5d0 +subtext0 928f9a +overlay2 7f7c86 +overlay1 6c6972 +overlay0 5a5860 +surface2 49474e +surface1 38373c +surface0 262529 +base 141317 +mantle 141317 +crust 131216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/shadotheme/default/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/shadotheme/default/dark.txt new file mode 100644 index 0000000..a249d7b --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/shadotheme/default/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 6f72ac +secondary_paletteKeyColor 75758e +tertiary_paletteKeyColor 9d648f +neutral_paletteKeyColor 78767b +neutral_variant_paletteKeyColor 777680 +background 131317 +onBackground e5e1e7 +surface 131317 +surfaceDim 131317 +surfaceBright 39393d +surfaceContainerLowest 0e0e11 +surfaceContainerLow 1b1b1f +surfaceContainer 1f1f23 +surfaceContainerHigh 2a292e +surfaceContainerHighest 353438 +onSurface e5e1e7 +surfaceVariant 46464f +onSurfaceVariant c7c5d1 +inverseSurface e5e1e7 +inverseOnSurface 303034 +outline 918f9a +outlineVariant 46464f +shadow 000000 +scrim 000000 +surfaceTint bfc1ff +primary bfc1ff +onPrimary 282b60 +primaryContainer 6f72ac +onPrimaryContainer 000028 +inversePrimary 565992 +secondary c5c4e0 +onSecondary 2e2f44 +secondaryContainer 44455c +onSecondaryContainer b3b3ce +tertiary f4b2e2 +onTertiary 4e1e45 +tertiaryContainer ba7eaa +onTertiaryContainer 000000 +error ffb4ab +onError 690005 +errorContainer 93000a +onErrorContainer ffdad6 +primaryFixed e0e0ff +primaryFixedDim bfc1ff +onPrimaryFixed 12144a +onPrimaryFixedVariant 3e4278 +secondaryFixed e1e0fd +secondaryFixedDim c5c4e0 +onSecondaryFixed 191a2e +onSecondaryFixedVariant 44455c +tertiaryFixed ffd7f1 +tertiaryFixedDim f4b2e2 +onTertiaryFixed 35082f +onTertiaryFixedVariant 67355d +term0 353434 +term1 a875ff +term2 44def5 +term3 ffdcf2 +term4 97aad7 +term5 b29feb +term6 9dceff +term7 e8d3de +term8 ac9fa9 +term9 bd95ff +term10 89ecff +term11 fff0f6 +term12 b4c1dc +term13 c8b5f5 +term14 bae0ff +term15 ffffff +rosewater f7eff9 +flamingo e8def3 +pink e1d8ff +mauve bdb9ff +red bfa6fe +maroon c7b6ed +peach e0c2f9 +yellow ffecf3 +green c8e3ff +teal d2e0ff +sky cedaff +sapphire b5c5ff +blue aeb8ff +lavender c6c8ff +klink 7083d2 +klinkSelection 6f83d2 +kvisited 7e73db +kvisitedSelection 7d73db +knegative 9d69ff +knegativeSelection 9b6aff +kneutral c794ff +kneutralSelection c794ff +kpositive 60adff +kpositiveSelection 60adff +text e5e1e7 +subtext1 c7c5d1 +subtext0 918f9a +overlay2 7e7c86 +overlay1 6b6972 +overlay0 595860 +surface2 48474e +surface1 37373d +surface0 25252a +base 131317 +mantle 131317 +crust 121216 +success B5CCBA +onSuccess 213528 +successContainer 374B3E +onSuccessContainer D1E9D6 \ No newline at end of file diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/solarized/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/solarized/medium/dark.txt new file mode 100644 index 0000000..7000788 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/solarized/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 268BD2 +secondary_paletteKeyColor 2AA198 +tertiary_paletteKeyColor 6C71C4 +neutral_paletteKeyColor 002B36 +neutral_variant_paletteKeyColor 073642 +background 002B36 +onBackground FDF6E3 +surface 073642 +surfaceDim 001F29 +surfaceBright 0D4250 +surfaceContainerLowest 00151D +surfaceContainerLow 0A404E +surfaceContainer 094B59 +surfaceContainerHigh 0D4250 +surfaceContainerHighest 11505E +onSurface FDF6E3 +surfaceVariant 094B59 +onSurfaceVariant 93A1A1 +inverseSurface FDF6E3 +inverseOnSurface 002B36 +outline 586E75 +outlineVariant 0D4250 +shadow 000000 +scrim 000000 +surfaceTint 268BD2 +primary 268BD2 +onPrimary 002B36 +primaryContainer 0D4250 +onPrimaryContainer 268BD2 +inversePrimary 2075B2 +secondary 2AA198 +onSecondary 002B36 +secondaryContainer 0D4250 +onSecondaryContainer 2AA198 +tertiary 6C71C4 +onTertiary 002B36 +tertiaryContainer 0D4250 +onTertiaryContainer 6C71C4 +error DC322F +onError 002B36 +errorContainer 4C3743 +onErrorContainer DC322F +primaryFixed 268BD2 +primaryFixedDim 2075B2 +onPrimaryFixed 002B36 +onPrimaryFixedVariant 094B59 +secondaryFixed 2AA198 +secondaryFixedDim 228178 +onSecondaryFixed 002B36 +onSecondaryFixedVariant 094B59 +tertiaryFixed 6C71C4 +tertiaryFixedDim 5C61A4 +onTertiaryFixed 002B36 +onTertiaryFixedVariant 094B59 +term0 002B36 +term1 DC322F +term2 859900 +term3 B58900 +term4 268BD2 +term5 D33682 +term6 2AA198 +term7 EEE8D5 +term8 586E75 +term9 CB4B16 +term10 859900 +term11 B58900 +term12 268BD2 +term13 6C71C4 +term14 2AA198 +term15 FDF6E3 +rosewater FDF6E3 +flamingo EEE8D5 +pink D33682 +mauve 6C71C4 +red DC322F +maroon CB4B16 +peach CB4B16 +yellow B58900 +green 859900 +teal 2AA198 +sky 2AA198 +sapphire 268BD2 +blue 268BD2 +lavender 6C71C4 +klink 268BD2 +klinkSelection 268BD2 +kvisited 6C71C4 +kvisitedSelection 6C71C4 +knegative DC322F +knegativeSelection DC322F +kneutral B58900 +kneutralSelection B58900 +kpositive 859900 +kpositiveSelection 859900 +text FDF6E3 +subtext1 93A1A1 +subtext0 839496 +overlay2 657B83 +overlay1 586E75 +overlay0 073642 +surface2 094B59 +surface1 073642 +surface0 002B36 +base 002B36 +mantle 001F29 +crust 00151D +success 859900 +onSuccess 002B36 +successContainer 0D4250 +onSuccessContainer FDF6E3 diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/tokyonight/medium/dark.txt b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/tokyonight/medium/dark.txt new file mode 100644 index 0000000..0fbb87a --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/assets/schemes/tokyonight/medium/dark.txt @@ -0,0 +1,110 @@ +primary_paletteKeyColor 7AA2F7 +secondary_paletteKeyColor 9ECE6A +tertiary_paletteKeyColor BB9AF7 +neutral_paletteKeyColor 1A1B26 +neutral_variant_paletteKeyColor 292E42 +background 1A1B26 +onBackground C0CAF5 +surface 24283B +surfaceDim 16161E +surfaceBright 3B4261 +surfaceContainerLowest 0F0F14 +surfaceContainerLow 2B3048 +surfaceContainer 2A2F41 +surfaceContainerHigh 3B4261 +surfaceContainerHighest 414868 +onSurface C0CAF5 +surfaceVariant 2A2F41 +onSurfaceVariant A9B1D6 +inverseSurface C0CAF5 +inverseOnSurface 1A1B26 +outline 565F89 +outlineVariant 3B4261 +shadow 000000 +scrim 000000 +surfaceTint 7AA2F7 +primary 7AA2F7 +onPrimary 1A1B26 +primaryContainer 3B4261 +onPrimaryContainer 7AA2F7 +inversePrimary 5A7FD7 +secondary 9ECE6A +onSecondary 1A1B26 +secondaryContainer 3B4261 +onSecondaryContainer 9ECE6A +tertiary BB9AF7 +onTertiary 1A1B26 +tertiaryContainer 3B4261 +onTertiaryContainer BB9AF7 +error F7768E +onError 1A1B26 +errorContainer 4C3743 +onErrorContainer F7768E +primaryFixed 7AA2F7 +primaryFixedDim 5A7FD7 +onPrimaryFixed 1A1B26 +onPrimaryFixedVariant 2A2F41 +secondaryFixed 9ECE6A +secondaryFixedDim 7EAE4A +onSecondaryFixed 1A1B26 +onSecondaryFixedVariant 2A2F41 +tertiaryFixed BB9AF7 +tertiaryFixedDim 9B7AD7 +onTertiaryFixed 1A1B26 +onTertiaryFixedVariant 2A2F41 +term0 1A1B26 +term1 F7768E +term2 9ECE6A +term3 E0AF68 +term4 7AA2F7 +term5 BB9AF7 +term6 7DCFFF +term7 C0CAF5 +term8 565F89 +term9 F7768E +term10 9ECE6A +term11 E0AF68 +term12 7AA2F7 +term13 BB9AF7 +term14 7DCFFF +term15 C0CAF5 +rosewater C0CAF5 +flamingo BB9AF7 +pink F7768E +mauve BB9AF7 +red F7768E +maroon E0AF68 +peach FF9E64 +yellow E0AF68 +green 9ECE6A +teal 1ABC9C +sky 7DCFFF +sapphire 2AC3DE +blue 7AA2F7 +lavender 7DCFFF +klink 7AA2F7 +klinkSelection 7AA2F7 +kvisited BB9AF7 +kvisitedSelection BB9AF7 +knegative F7768E +knegativeSelection F7768E +kneutral E0AF68 +kneutralSelection E0AF68 +kpositive 9ECE6A +kpositiveSelection 9ECE6A +text C0CAF5 +subtext1 A9B1D6 +subtext0 9AA5CE +overlay2 787C99 +overlay1 696D85 +overlay0 565F89 +surface2 2A2F41 +surface1 24283B +surface0 1A1B26 +base 1A1B26 +mantle 16161E +crust 0F0F14 +success 9ECE6A +onSuccess 1A1B26 +successContainer 3B4261 +onSuccessContainer C0CAF5 diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/scheme.cpython-314.opt-1.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/scheme.cpython-314.opt-1.pyc new file mode 100644 index 0000000..fdae984 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/scheme.cpython-314.opt-1.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/scheme.cpython-314.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/scheme.cpython-314.pyc new file mode 100644 index 0000000..fdae984 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/scheme.cpython-314.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/screenshot.cpython-314.opt-1.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/screenshot.cpython-314.opt-1.pyc new file mode 100644 index 0000000..be1ea17 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/screenshot.cpython-314.opt-1.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc new file mode 100644 index 0000000..be1ea17 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/screenshot.cpython-314.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/shell.cpython-314.opt-1.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/shell.cpython-314.opt-1.pyc new file mode 100644 index 0000000..07e01c8 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/shell.cpython-314.opt-1.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/shell.cpython-314.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/shell.cpython-314.pyc new file mode 100644 index 0000000..07e01c8 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/shell.cpython-314.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/wallpaper.cpython-314.opt-1.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/wallpaper.cpython-314.opt-1.pyc new file mode 100644 index 0000000..f6702d2 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/wallpaper.cpython-314.opt-1.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/wallpaper.cpython-314.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/wallpaper.cpython-314.pyc new file mode 100644 index 0000000..f6702d2 Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/__pycache__/wallpaper.cpython-314.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/scheme.py b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/scheme.py new file mode 100644 index 0000000..c1db4e1 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/scheme.py @@ -0,0 +1,139 @@ +from typing import Annotated, Optional +import typer +import json + +from zshell.utils.schemepalettes import PRESETS +from pathlib import Path +from PIL import Image +from materialyoucolor.quantize import QuantizeCelebi +from materialyoucolor.score.score import Score +from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors +from materialyoucolor.hct.hct import Hct + +app = typer.Typer() + + +@app.command() +def generate( + # image inputs (optional - used for image mode) + image_path: Optional[Path] = typer.Option( + None, help="Path to source image. Required for image mode."), + thumbnail_path: Optional[Path] = typer.Option( + Path("thumb.jpg"), help="Path to temporary thumbnail (image mode)."), + scheme: Optional[str] = typer.Option( + "fruit-salad", help="Color scheme algorithm to use for image mode. Ignored in preset mode."), + # preset inputs (optional - used for preset mode) + preset: Optional[str] = typer.Option( + None, help="Name of a premade scheme in this format: :"), + mode: str = typer.Option( + "dark", help="Mode of the preset scheme (dark or light)."), + # output (required) + output: Path = typer.Option(..., help="Output JSON path.") +): + if preset is None and image_path is None: + raise typer.BadParameter( + "Either --image-path or --preset must be provided.") + + if preset is not None and image_path is not None: + raise typer.BadParameter( + "Use either --image-path or --preset, not both.") + + match scheme: + case "fruit-salad": + from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme + case 'expressive': + from materialyoucolor.scheme.scheme_expressive import SchemeExpressive as Scheme + case 'monochrome': + from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme + case 'rainbow': + from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme + case 'tonal-spot': + from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme + case 'neutral': + from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme + case 'fidelity': + from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity as Scheme + case 'content': + from materialyoucolor.scheme.scheme_content import SchemeContent as Scheme + case 'vibrant': + from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme + case _: + from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme + + def generate_thumbnail(image_path, thumbnail_path, size=(128, 128)): + thumbnail_file = Path(thumbnail_path) + + image = Image.open(image_path) + image = image.convert("RGB") + image.thumbnail(size, Image.NEAREST) + + thumbnail_file.parent.mkdir(parents=True, exist_ok=True) + image.save(thumbnail_path, "JPEG") + + def seed_from_image(image_path: Path) -> Hct: + image = Image.open(image_path) + pixel_len = image.width * image.height + image_data = image.getdata() + + quality = 1 + pixel_array = [image_data[_] for _ in range(0, pixel_len, quality)] + + result = QuantizeCelebi(pixel_array, 128) + return Hct.from_int(Score.score(result)[0]) + + def seed_from_preset(name: str) -> Hct: + try: + return PRESETS[name].primary + except KeyError: + raise typer.BadParameter( + f"Preset '{name}' not found. Available presets: {', '.join(PRESETS.keys())}") + + def generate_color_scheme(seed: Hct, mode: str) -> dict[str, str]: + + is_dark = mode.lower() == "dark" + + scheme = Scheme( + seed, + is_dark, + 0.0 + ) + + color_dict = {} + for color in vars(MaterialDynamicColors).keys(): + color_name = getattr(MaterialDynamicColors, color) + if hasattr(color_name, "get_hct"): + color_int = color_name.get_hct(scheme).to_int() + color_dict[color] = int_to_hex(color_int) + + return color_dict + + def int_to_hex(argb_int): + return "#{:06X}".format(argb_int & 0xFFFFFF) + + try: + if preset: + seed = seed_from_preset(preset) + colors = generate_color_scheme(seed, mode) + name, flavor = preset.split(":") + else: + generate_thumbnail(image_path, str(thumbnail_path)) + seed = seed_from_image(thumbnail_path) + colors = generate_color_scheme(seed, mode) + name = "dynamic" + flavor = "default" + + output_dict = { + "name": name, + "flavor": flavor, + "mode": mode, + "variant": scheme, + "colors": colors + } + + output.parent.mkdir(parents=True, exist_ok=True) + with open(output, "w") as f: + json.dump(output_dict, f, indent=4) + except Exception as e: + print(f"Error: {e}") + # with open(output, "w") as f: + # f.write(f"Error: {e}") diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/screenshot.py b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/screenshot.py new file mode 100644 index 0000000..8edcb7f --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/screenshot.py @@ -0,0 +1,18 @@ +import subprocess +import typer + +args = ["qs", "-c", "zshell"] + +app = typer.Typer() + + +@app.command() +def start(): + subprocess.run(args + ["ipc"] + ["call"] + + ["picker"] + ["open"], check=True) + + +@app.command() +def start_freeze(): + subprocess.run(args + ["ipc"] + ["call"] + + ["picker"] + ["openFreeze"], check=True) diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/shell.py b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/shell.py new file mode 100644 index 0000000..156e8d2 --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/shell.py @@ -0,0 +1,37 @@ +import subprocess +import typer + +args = ["qs", "-c", "zshell"] + +app = typer.Typer() + + +@app.command() +def kill(): + subprocess.run(args + ["kill"], check=True) + + +@app.command() +def start(no_daemon: bool = False): + subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), check=True) + + +@app.command() +def show(): + subprocess.run(args + ["ipc"] + ["show"], check=True) + + +@app.command() +def log(): + subprocess.run(args + ["log"], check=True) + + +@app.command() +def lock(): + subprocess.run(args + ["ipc"] + ["call"] + ["lock"] + ["lock"], check=True) + + +@app.command() +def call(target: str, method: str, method_args: list[str] = typer.Argument(None)): + subprocess.run(args + ["ipc"] + ["call"] + [target] + + [method] + method_args, check=True) diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/wallpaper.py b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/wallpaper.py new file mode 100644 index 0000000..946926d --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/subcommands/wallpaper.py @@ -0,0 +1,40 @@ +import subprocess +import typer + +from typing import Annotated +from PIL import Image, ImageFilter +from pathlib import Path + +args = ["qs", "-c", "zshell"] + +app = typer.Typer() + + +@app.command() +def set(wallpaper: Path): + subprocess.run(args + ["ipc"] + ["call"] + + ["wallpaper"] + ["set"] + [wallpaper], check=True) + + +@app.command() +def lockscreen( + input_image: Annotated[ + Path, + typer.Option(), + ], + output_path: Annotated[ + Path, + typer.Option(), + ], + blur_amount: int = 20 +): + img = Image.open(input_image) + size = img.size + if (size[0] < 3840 or size[1] < 2160): + img = img.resize((size[0] // 2, size[1] // 2), Image.NEAREST) + else: + img = img.resize((size[0] // 4, size[1] // 4), Image.NEAREST) + + img = img.filter(ImageFilter.GaussianBlur(blur_amount)) + + img.save(output_path, "PNG") diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/__pycache__/schemepalettes.cpython-314.opt-1.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/__pycache__/schemepalettes.cpython-314.opt-1.pyc new file mode 100644 index 0000000..514350e Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/__pycache__/schemepalettes.cpython-314.opt-1.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/__pycache__/schemepalettes.cpython-314.pyc b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/__pycache__/schemepalettes.cpython-314.pyc new file mode 100644 index 0000000..514350e Binary files /dev/null and b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/__pycache__/schemepalettes.cpython-314.pyc differ diff --git a/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/schemepalettes.py b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/schemepalettes.py new file mode 100644 index 0000000..00227be --- /dev/null +++ b/pkg/zshell/usr/lib/python3.14/site-packages/zshell/utils/schemepalettes.py @@ -0,0 +1,30 @@ +from dataclasses import dataclass +from materialyoucolor.hct.hct import Hct +from typing import Mapping + + +@dataclass(frozen=True) +class SeedPalette: + primary: Hct + secondary: Hct + tertiary: Hct + neutral: Hct + neutral_variant: Hct + error: Hct | None = None + + +def hex_to_hct(hex_: str) -> Hct: + return Hct.from_int(int(f"0xFF{hex_}", 16)) + + +CATPPUCCIN_MACCHIATO = SeedPalette( + primary=hex_to_hct("C6A0F6"), + secondary=hex_to_hct("7DC4E4"), + tertiary=hex_to_hct("F5BDE6"), + neutral=hex_to_hct("24273A"), + neutral_variant=hex_to_hct("363A4F"), +) + +PRESETS: Mapping[str, SeedPalette] = { + "catppuccin:macchiato": CATPPUCCIN_MACCHIATO, +} diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/ZShell-internal.qmltypes b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/ZShell-internal.qmltypes new file mode 100644 index 0000000..715fac9 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/ZShell-internal.qmltypes @@ -0,0 +1,317 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "cachingimagemanager.hpp" + lineNumber: 9 + name: "ZShell::internal::CachingImageManager" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell.Internal/CachingImageManager 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "item" + type: "QQuickItem" + isPointer: true + read: "item" + write: "setItem" + notify: "itemChanged" + index: 0 + lineNumber: 13 + isRequired: true + } + Property { + name: "cacheDir" + type: "QUrl" + read: "cacheDir" + write: "setCacheDir" + notify: "cacheDirChanged" + index: 1 + lineNumber: 14 + isRequired: true + } + Property { + name: "path" + type: "QString" + read: "path" + write: "setPath" + notify: "pathChanged" + index: 2 + lineNumber: 16 + } + Property { + name: "cachePath" + type: "QUrl" + read: "cachePath" + notify: "cachePathChanged" + index: 3 + lineNumber: 17 + isReadonly: true + } + Signal { name: "itemChanged"; lineNumber: 39 } + Signal { name: "cacheDirChanged"; lineNumber: 40 } + Signal { name: "pathChanged"; lineNumber: 42 } + Signal { name: "cachePathChanged"; lineNumber: 43 } + Signal { name: "usingCacheChanged"; lineNumber: 44 } + Method { name: "updateSource"; lineNumber: 35 } + Method { + name: "updateSource" + lineNumber: 36 + Parameter { name: "path"; type: "QString" } + } + } + Component { + file: "circularindicatormanager.hpp" + lineNumber: 9 + name: "ZShell::internal::CircularIndicatorManager" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell.Internal/CircularIndicatorManager 1.0"] + exportMetaObjectRevisions: [256] + Enum { + name: "IndeterminateAnimationType" + lineNumber: 27 + values: ["Advance", "Retreat"] + } + Property { + name: "startFraction" + type: "double" + read: "startFraction" + notify: "startFractionChanged" + index: 0 + lineNumber: 13 + isReadonly: true + } + Property { + name: "endFraction" + type: "double" + read: "endFraction" + notify: "endFractionChanged" + index: 1 + lineNumber: 14 + isReadonly: true + } + Property { + name: "rotation" + type: "double" + read: "rotation" + notify: "rotationChanged" + index: 2 + lineNumber: 15 + isReadonly: true + } + Property { + name: "progress" + type: "double" + read: "progress" + write: "setProgress" + notify: "progressChanged" + index: 3 + lineNumber: 16 + } + Property { + name: "completeEndProgress" + type: "double" + read: "completeEndProgress" + write: "setCompleteEndProgress" + notify: "completeEndProgressChanged" + index: 4 + lineNumber: 17 + } + Property { + name: "duration" + type: "double" + read: "duration" + notify: "indeterminateAnimationTypeChanged" + index: 5 + lineNumber: 19 + isReadonly: true + } + Property { + name: "completeEndDuration" + type: "double" + read: "completeEndDuration" + notify: "indeterminateAnimationTypeChanged" + index: 6 + lineNumber: 20 + isReadonly: true + } + Property { + name: "indeterminateAnimationType" + type: "IndeterminateAnimationType" + read: "indeterminateAnimationType" + write: "setIndeterminateAnimationType" + notify: "indeterminateAnimationTypeChanged" + index: 7 + lineNumber: 21 + } + Signal { name: "startFractionChanged"; lineNumber: 50 } + Signal { name: "endFractionChanged"; lineNumber: 51 } + Signal { name: "rotationChanged"; lineNumber: 52 } + Signal { name: "progressChanged"; lineNumber: 53 } + Signal { name: "completeEndProgressChanged"; lineNumber: 54 } + Signal { name: "indeterminateAnimationTypeChanged"; lineNumber: 55 } + } + Component { + file: "hyprdevices.hpp" + lineNumber: 52 + name: "ZShell::internal::hypr::HyprDevices" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell.Internal/HyprDevices 1.0"] + isCreatable: false + exportMetaObjectRevisions: [256] + Property { + name: "keyboards" + type: "ZShell::internal::hypr::HyprKeyboard" + isList: true + read: "keyboards" + notify: "keyboardsChanged" + index: 0 + lineNumber: 57 + isReadonly: true + } + Signal { name: "keyboardsChanged"; lineNumber: 68 } + } + Component { + file: "hyprextras.hpp" + lineNumber: 10 + name: "ZShell::internal::hypr::HyprExtras" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell.Internal/HyprExtras 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "options" + type: "QVariantHash" + read: "options" + notify: "optionsChanged" + index: 0 + lineNumber: 14 + isReadonly: true + } + Property { + name: "devices" + type: "ZShell::internal::hypr::HyprDevices" + isPointer: true + read: "devices" + index: 1 + lineNumber: 15 + isReadonly: true + isPropertyConstant: true + } + Signal { name: "optionsChanged"; lineNumber: 31 } + Method { + name: "message" + lineNumber: 23 + Parameter { name: "message"; type: "QString" } + } + Method { + name: "batchMessage" + lineNumber: 24 + Parameter { name: "messages"; type: "QStringList" } + } + Method { + name: "applyOptions" + lineNumber: 25 + Parameter { name: "options"; type: "QVariantHash" } + } + Method { name: "refreshOptions"; lineNumber: 27 } + Method { name: "refreshDevices"; lineNumber: 28 } + } + Component { + file: "hyprdevices.hpp" + lineNumber: 10 + name: "ZShell::internal::hypr::HyprKeyboard" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell.Internal/HyprKeyboard 1.0"] + isCreatable: false + exportMetaObjectRevisions: [256] + Property { + name: "lastIpcObject" + type: "QVariantHash" + read: "lastIpcObject" + notify: "lastIpcObjectChanged" + index: 0 + lineNumber: 15 + isReadonly: true + } + Property { + name: "address" + type: "QString" + read: "address" + notify: "addressChanged" + index: 1 + lineNumber: 16 + isReadonly: true + } + Property { + name: "name" + type: "QString" + read: "name" + notify: "nameChanged" + index: 2 + lineNumber: 17 + isReadonly: true + } + Property { + name: "layout" + type: "QString" + read: "layout" + notify: "layoutChanged" + index: 3 + lineNumber: 18 + isReadonly: true + } + Property { + name: "activeKeymap" + type: "QString" + read: "activeKeymap" + notify: "activeKeymapChanged" + index: 4 + lineNumber: 19 + isReadonly: true + } + Property { + name: "capsLock" + type: "bool" + read: "capsLock" + notify: "capsLockChanged" + index: 5 + lineNumber: 20 + isReadonly: true + } + Property { + name: "numLock" + type: "bool" + read: "numLock" + notify: "numLockChanged" + index: 6 + lineNumber: 21 + isReadonly: true + } + Property { + name: "main" + type: "bool" + read: "main" + notify: "mainChanged" + index: 7 + lineNumber: 22 + isReadonly: true + } + Signal { name: "lastIpcObjectChanged"; lineNumber: 39 } + Signal { name: "addressChanged"; lineNumber: 40 } + Signal { name: "nameChanged"; lineNumber: 41 } + Signal { name: "layoutChanged"; lineNumber: 42 } + Signal { name: "activeKeymapChanged"; lineNumber: 43 } + Signal { name: "capsLockChanged"; lineNumber: 44 } + Signal { name: "numLockChanged"; lineNumber: 45 } + Signal { name: "mainChanged"; lineNumber: 46 } + } +} diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/libZShell-internal.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/libZShell-internal.so new file mode 100755 index 0000000..249983e Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/libZShell-internal.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/libZShell-internalplugin.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/libZShell-internalplugin.so new file mode 100755 index 0000000..5683de9 Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/libZShell-internalplugin.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/qmldir b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/qmldir new file mode 100644 index 0000000..dee2e75 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/Internal/qmldir @@ -0,0 +1,8 @@ +module ZShell.Internal +linktarget ZShell-internalplugin +optional plugin ZShell-internalplugin +classname ZShell_InternalPlugin +typeinfo ZShell-internal.qmltypes +prefer :/qt/qml/ZShell/Internal/ +depends QtQuick + diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/ZShell-models.qmltypes b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/ZShell-models.qmltypes new file mode 100644 index 0000000..ea65aa3 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/ZShell-models.qmltypes @@ -0,0 +1,764 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "qabstractitemmodel.h" + lineNumber: 259 + name: "QAbstractItemModel" + accessSemantics: "reference" + prototype: "QObject" + Enum { + name: "LayoutChangeHint" + lineNumber: 335 + values: [ + "NoLayoutChangeHint", + "VerticalSortHint", + "HorizontalSortHint" + ] + } + Enum { + name: "CheckIndexOption" + isScoped: true + lineNumber: 343 + values: [ + "NoOption", + "IndexIsValid", + "DoNotUseParent", + "ParentIsInvalid" + ] + } + Signal { + name: "dataChanged" + lineNumber: 357 + Parameter { name: "topLeft"; type: "QModelIndex" } + Parameter { name: "bottomRight"; type: "QModelIndex" } + Parameter { name: "roles"; type: "int"; isList: true } + } + Signal { + name: "dataChanged" + isCloned: true + lineNumber: 357 + Parameter { name: "topLeft"; type: "QModelIndex" } + Parameter { name: "bottomRight"; type: "QModelIndex" } + } + Signal { + name: "headerDataChanged" + lineNumber: 359 + Parameter { name: "orientation"; type: "Qt::Orientation" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "layoutChanged" + lineNumber: 360 + Parameter { name: "parents"; type: "QPersistentModelIndex"; isList: true } + Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } + } + Signal { + name: "layoutChanged" + isCloned: true + lineNumber: 360 + Parameter { name: "parents"; type: "QPersistentModelIndex"; isList: true } + } + Signal { name: "layoutChanged"; isCloned: true; lineNumber: 360 } + Signal { + name: "layoutAboutToBeChanged" + lineNumber: 361 + Parameter { name: "parents"; type: "QPersistentModelIndex"; isList: true } + Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } + } + Signal { + name: "layoutAboutToBeChanged" + isCloned: true + lineNumber: 361 + Parameter { name: "parents"; type: "QPersistentModelIndex"; isList: true } + } + Signal { name: "layoutAboutToBeChanged"; isCloned: true; lineNumber: 361 } + Signal { + name: "rowsAboutToBeInserted" + lineNumber: 363 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsInserted" + lineNumber: 364 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsAboutToBeRemoved" + lineNumber: 366 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsRemoved" + lineNumber: 367 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsAboutToBeInserted" + lineNumber: 369 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsInserted" + lineNumber: 370 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsAboutToBeRemoved" + lineNumber: 372 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsRemoved" + lineNumber: 373 + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { name: "modelAboutToBeReset"; lineNumber: 375 } + Signal { name: "modelReset"; lineNumber: 376 } + Signal { + name: "rowsAboutToBeMoved" + lineNumber: 378 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationRow"; type: "int" } + } + Signal { + name: "rowsMoved" + lineNumber: 379 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationRow"; type: "int" } + } + Signal { + name: "columnsAboutToBeMoved" + lineNumber: 381 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationColumn"; type: "int" } + } + Signal { + name: "columnsMoved" + lineNumber: 382 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationColumn"; type: "int" } + } + Method { name: "submit"; type: "bool"; lineNumber: 385 } + Method { name: "revert"; lineNumber: 386 } + Method { name: "resetInternalData"; lineNumber: 389 } + Method { + name: "hasIndex" + type: "bool" + isMethodConstant: true + lineNumber: 271 + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "hasIndex" + type: "bool" + isCloned: true + isMethodConstant: true + lineNumber: 271 + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + } + Method { + name: "index" + type: "QModelIndex" + isMethodConstant: true + lineNumber: 272 + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "index" + type: "QModelIndex" + isCloned: true + isMethodConstant: true + lineNumber: 272 + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + } + Method { + name: "parent" + type: "QModelIndex" + isMethodConstant: true + lineNumber: 274 + Parameter { name: "child"; type: "QModelIndex" } + } + Method { + name: "sibling" + type: "QModelIndex" + isMethodConstant: true + lineNumber: 276 + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "idx"; type: "QModelIndex" } + } + Method { + name: "rowCount" + type: "int" + isMethodConstant: true + lineNumber: 277 + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { name: "rowCount"; type: "int"; isCloned: true; isMethodConstant: true; lineNumber: 277 } + Method { + name: "columnCount" + type: "int" + isMethodConstant: true + lineNumber: 278 + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "columnCount" + type: "int" + isCloned: true + isMethodConstant: true + lineNumber: 278 + } + Method { + name: "hasChildren" + type: "bool" + isMethodConstant: true + lineNumber: 279 + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "hasChildren" + type: "bool" + isCloned: true + isMethodConstant: true + lineNumber: 279 + } + Method { + name: "data" + type: "QVariant" + isMethodConstant: true + lineNumber: 281 + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "data" + type: "QVariant" + isCloned: true + isMethodConstant: true + lineNumber: 281 + Parameter { name: "index"; type: "QModelIndex" } + } + Method { + name: "setData" + type: "bool" + lineNumber: 282 + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "setData" + type: "bool" + isCloned: true + lineNumber: 282 + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "value"; type: "QVariant" } + } + Method { + name: "headerData" + type: "QVariant" + isMethodConstant: true + lineNumber: 284 + Parameter { name: "section"; type: "int" } + Parameter { name: "orientation"; type: "Qt::Orientation" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "headerData" + type: "QVariant" + isCloned: true + isMethodConstant: true + lineNumber: 284 + Parameter { name: "section"; type: "int" } + Parameter { name: "orientation"; type: "Qt::Orientation" } + } + Method { + name: "insertRows" + revision: 1540 + type: "bool" + lineNumber: 302 + Parameter { name: "row"; type: "int" } + Parameter { name: "count"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "insertRows" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 302 + Parameter { name: "row"; type: "int" } + Parameter { name: "count"; type: "int" } + } + Method { + name: "insertColumns" + revision: 1540 + type: "bool" + lineNumber: 303 + Parameter { name: "column"; type: "int" } + Parameter { name: "count"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "insertColumns" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 303 + Parameter { name: "column"; type: "int" } + Parameter { name: "count"; type: "int" } + } + Method { + name: "removeRows" + revision: 1540 + type: "bool" + lineNumber: 304 + Parameter { name: "row"; type: "int" } + Parameter { name: "count"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "removeRows" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 304 + Parameter { name: "row"; type: "int" } + Parameter { name: "count"; type: "int" } + } + Method { + name: "removeColumns" + revision: 1540 + type: "bool" + lineNumber: 305 + Parameter { name: "column"; type: "int" } + Parameter { name: "count"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "removeColumns" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 305 + Parameter { name: "column"; type: "int" } + Parameter { name: "count"; type: "int" } + } + Method { + name: "moveRows" + revision: 1540 + type: "bool" + lineNumber: 306 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceRow"; type: "int" } + Parameter { name: "count"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationChild"; type: "int" } + } + Method { + name: "moveColumns" + revision: 1540 + type: "bool" + lineNumber: 308 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceColumn"; type: "int" } + Parameter { name: "count"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationChild"; type: "int" } + } + Method { + name: "insertRow" + revision: 1540 + type: "bool" + lineNumber: 311 + Parameter { name: "row"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "insertRow" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 311 + Parameter { name: "row"; type: "int" } + } + Method { + name: "insertColumn" + revision: 1540 + type: "bool" + lineNumber: 312 + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "insertColumn" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 312 + Parameter { name: "column"; type: "int" } + } + Method { + name: "removeRow" + revision: 1540 + type: "bool" + lineNumber: 313 + Parameter { name: "row"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "removeRow" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 313 + Parameter { name: "row"; type: "int" } + } + Method { + name: "removeColumn" + revision: 1540 + type: "bool" + lineNumber: 314 + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "removeColumn" + revision: 1540 + type: "bool" + isCloned: true + lineNumber: 314 + Parameter { name: "column"; type: "int" } + } + Method { + name: "moveRow" + revision: 1540 + type: "bool" + lineNumber: 315 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceRow"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationChild"; type: "int" } + } + Method { + name: "moveColumn" + revision: 1540 + type: "bool" + lineNumber: 317 + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceColumn"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationChild"; type: "int" } + } + Method { + name: "fetchMore" + lineNumber: 320 + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "canFetchMore" + type: "bool" + isMethodConstant: true + lineNumber: 321 + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "flags" + type: "Qt::ItemFlags" + isMethodConstant: true + lineNumber: 322 + Parameter { name: "index"; type: "QModelIndex" } + } + Method { + name: "sort" + revision: 1540 + lineNumber: 323 + Parameter { name: "column"; type: "int" } + Parameter { name: "order"; type: "Qt::SortOrder" } + } + Method { + name: "sort" + revision: 1540 + isCloned: true + lineNumber: 323 + Parameter { name: "column"; type: "int" } + } + Method { + name: "match" + type: "QModelIndexList" + isMethodConstant: true + lineNumber: 325 + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "hits"; type: "int" } + Parameter { name: "flags"; type: "Qt::MatchFlags" } + } + Method { + name: "match" + type: "QModelIndexList" + isCloned: true + isMethodConstant: true + lineNumber: 325 + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "hits"; type: "int" } + } + Method { + name: "match" + type: "QModelIndexList" + isCloned: true + isMethodConstant: true + lineNumber: 325 + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + } + } + Component { + file: "qabstractitemmodel.h" + lineNumber: 477 + name: "QAbstractListModel" + accessSemantics: "reference" + prototype: "QAbstractItemModel" + } + Component { + file: "filesystemmodel.hpp" + lineNumber: 15 + name: "ZShell::models::FileSystemEntry" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell.Models/FileSystemEntry 1.0"] + isCreatable: false + exportMetaObjectRevisions: [256] + Property { + name: "path" + type: "QString" + read: "path" + index: 0 + lineNumber: 20 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "relativePath" + type: "QString" + read: "relativePath" + notify: "relativePathChanged" + index: 1 + lineNumber: 21 + isReadonly: true + } + Property { + name: "name" + type: "QString" + read: "name" + index: 2 + lineNumber: 22 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "baseName" + type: "QString" + read: "baseName" + index: 3 + lineNumber: 23 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "parentDir" + type: "QString" + read: "parentDir" + index: 4 + lineNumber: 24 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "suffix" + type: "QString" + read: "suffix" + index: 5 + lineNumber: 25 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "size" + type: "qlonglong" + read: "size" + index: 6 + lineNumber: 26 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "isDir" + type: "bool" + read: "isDir" + index: 7 + lineNumber: 27 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "isImage" + type: "bool" + read: "isImage" + index: 8 + lineNumber: 28 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "mimeType" + type: "QString" + read: "mimeType" + index: 9 + lineNumber: 29 + isReadonly: true + isPropertyConstant: true + } + Signal { name: "relativePathChanged"; lineNumber: 48 } + } + Component { + file: "filesystemmodel.hpp" + lineNumber: 63 + name: "ZShell::models::FileSystemModel" + accessSemantics: "reference" + prototype: "QAbstractListModel" + exports: ["ZShell.Models/FileSystemModel 1.0"] + exportMetaObjectRevisions: [256] + Enum { + name: "Filter" + lineNumber: 78 + values: ["NoFilter", "Images", "Files", "Dirs"] + } + Property { + name: "path" + type: "QString" + read: "path" + write: "setPath" + notify: "pathChanged" + index: 0 + lineNumber: 67 + } + Property { + name: "recursive" + type: "bool" + read: "recursive" + write: "setRecursive" + notify: "recursiveChanged" + index: 1 + lineNumber: 68 + } + Property { + name: "watchChanges" + type: "bool" + read: "watchChanges" + write: "setWatchChanges" + notify: "watchChangesChanged" + index: 2 + lineNumber: 69 + } + Property { + name: "showHidden" + type: "bool" + read: "showHidden" + write: "setShowHidden" + notify: "showHiddenChanged" + index: 3 + lineNumber: 70 + } + Property { + name: "sortReverse" + type: "bool" + read: "sortReverse" + write: "setSortReverse" + notify: "sortReverseChanged" + index: 4 + lineNumber: 71 + } + Property { + name: "filter" + type: "Filter" + read: "filter" + write: "setFilter" + notify: "filterChanged" + index: 5 + lineNumber: 72 + } + Property { + name: "nameFilters" + type: "QStringList" + read: "nameFilters" + write: "setNameFilters" + notify: "nameFiltersChanged" + index: 6 + lineNumber: 73 + } + Property { + name: "entries" + type: "ZShell::models::FileSystemEntry" + isList: true + read: "entries" + notify: "entriesChanged" + index: 7 + lineNumber: 75 + isReadonly: true + } + Signal { name: "pathChanged"; lineNumber: 116 } + Signal { name: "recursiveChanged"; lineNumber: 117 } + Signal { name: "watchChangesChanged"; lineNumber: 118 } + Signal { name: "showHiddenChanged"; lineNumber: 119 } + Signal { name: "sortReverseChanged"; lineNumber: 120 } + Signal { name: "filterChanged"; lineNumber: 121 } + Signal { name: "nameFiltersChanged"; lineNumber: 122 } + Signal { name: "entriesChanged"; lineNumber: 123 } + } +} diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/libZShell-models.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/libZShell-models.so new file mode 100755 index 0000000..08d105b Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/libZShell-models.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/libZShell-modelsplugin.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/libZShell-modelsplugin.so new file mode 100755 index 0000000..a0f31cd Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/libZShell-modelsplugin.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/qmldir b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/qmldir new file mode 100644 index 0000000..28100d3 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/Models/qmldir @@ -0,0 +1,7 @@ +module ZShell.Models +linktarget ZShell-modelsplugin +optional plugin ZShell-modelsplugin +classname ZShell_ModelsPlugin +typeinfo ZShell-models.qmltypes +prefer :/qt/qml/ZShell/Models/ + diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/ZShell-services.qmltypes b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/ZShell-services.qmltypes new file mode 100644 index 0000000..c479f91 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/ZShell-services.qmltypes @@ -0,0 +1,67 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "audioprovider.hpp" + lineNumber: 29 + name: "ZShell::services::AudioProvider" + accessSemantics: "reference" + prototype: "ZShell::services::Service" + } + Component { + file: "beattracker.hpp" + lineNumber: 28 + name: "ZShell::services::BeatTracker" + accessSemantics: "reference" + prototype: "ZShell::services::AudioProvider" + exports: ["ZShell.Services/BeatTracker 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "bpm" + type: "smpl_t" + read: "bpm" + notify: "bpmChanged" + index: 0 + lineNumber: 32 + isReadonly: true + } + Signal { name: "bpmChanged"; lineNumber: 40 } + Signal { + name: "beat" + lineNumber: 41 + Parameter { name: "bpm"; type: "smpl_t" } + } + } + Component { + file: "service.hpp" + lineNumber: 8 + name: "ZShell::services::Service" + accessSemantics: "reference" + prototype: "QObject" + } + Component { + file: "serviceref.hpp" + lineNumber: 9 + name: "ZShell::services::ServiceRef" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell.Services/ServiceRef 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "service" + type: "ZShell::services::Service" + isPointer: true + read: "service" + write: "setService" + notify: "serviceChanged" + index: 0 + lineNumber: 13 + } + Signal { name: "serviceChanged"; lineNumber: 22 } + } +} diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/libZShell-services.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/libZShell-services.so new file mode 100755 index 0000000..093ee87 Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/libZShell-services.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/libZShell-servicesplugin.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/libZShell-servicesplugin.so new file mode 100755 index 0000000..93670ab Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/libZShell-servicesplugin.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/qmldir b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/qmldir new file mode 100644 index 0000000..2cb4503 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/Services/qmldir @@ -0,0 +1,7 @@ +module ZShell.Services +linktarget ZShell-servicesplugin +optional plugin ZShell-servicesplugin +classname ZShell_ServicesPlugin +typeinfo ZShell-services.qmltypes +prefer :/qt/qml/ZShell/Services/ + diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/ZShell.qmltypes b/pkg/zshell/usr/lib/qt6/qml/ZShell/ZShell.qmltypes new file mode 100644 index 0000000..97e1333 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/ZShell.qmltypes @@ -0,0 +1,488 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "appdb.hpp" + lineNumber: 62 + name: "ZShell::AppDb" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell/AppDb 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "uuid" + type: "QString" + read: "uuid" + index: 0 + lineNumber: 66 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "path" + type: "QString" + read: "path" + write: "setPath" + notify: "pathChanged" + index: 1 + lineNumber: 67 + isRequired: true + } + Property { + name: "entries" + type: "QObjectList" + read: "entries" + write: "setEntries" + notify: "entriesChanged" + index: 2 + lineNumber: 68 + isRequired: true + } + Property { + name: "apps" + type: "ZShell::AppEntry" + isList: true + read: "apps" + notify: "appsChanged" + index: 3 + lineNumber: 69 + isReadonly: true + } + Signal { name: "pathChanged"; lineNumber: 87 } + Signal { name: "entriesChanged"; lineNumber: 88 } + Signal { name: "appsChanged"; lineNumber: 89 } + Method { + name: "incrementFrequency" + lineNumber: 84 + Parameter { name: "id"; type: "QString" } + } + } + Component { + file: "appdb.hpp" + lineNumber: 11 + name: "ZShell::AppEntry" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell/AppEntry 1.0"] + isCreatable: false + exportMetaObjectRevisions: [256] + Property { + name: "entry" + type: "QObject" + isPointer: true + read: "entry" + index: 0 + lineNumber: 17 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "frequency" + type: "uint" + read: "frequency" + notify: "frequencyChanged" + index: 1 + lineNumber: 19 + isReadonly: true + } + Property { + name: "id" + type: "QString" + read: "id" + index: 2 + lineNumber: 20 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "name" + type: "QString" + read: "name" + notify: "nameChanged" + index: 3 + lineNumber: 21 + isReadonly: true + } + Property { + name: "comment" + type: "QString" + read: "comment" + notify: "commentChanged" + index: 4 + lineNumber: 22 + isReadonly: true + } + Property { + name: "execString" + type: "QString" + read: "execString" + notify: "execStringChanged" + index: 5 + lineNumber: 23 + isReadonly: true + } + Property { + name: "startupClass" + type: "QString" + read: "startupClass" + notify: "startupClassChanged" + index: 6 + lineNumber: 24 + isReadonly: true + } + Property { + name: "genericName" + type: "QString" + read: "genericName" + notify: "genericNameChanged" + index: 7 + lineNumber: 25 + isReadonly: true + } + Property { + name: "categories" + type: "QString" + read: "categories" + notify: "categoriesChanged" + index: 8 + lineNumber: 26 + isReadonly: true + } + Property { + name: "keywords" + type: "QString" + read: "keywords" + notify: "keywordsChanged" + index: 9 + lineNumber: 27 + isReadonly: true + } + Signal { name: "frequencyChanged"; lineNumber: 48 } + Signal { name: "nameChanged"; lineNumber: 49 } + Signal { name: "commentChanged"; lineNumber: 50 } + Signal { name: "execStringChanged"; lineNumber: 51 } + Signal { name: "startupClassChanged"; lineNumber: 52 } + Signal { name: "genericNameChanged"; lineNumber: 53 } + Signal { name: "categoriesChanged"; lineNumber: 54 } + Signal { name: "keywordsChanged"; lineNumber: 55 } + } + Component { + file: "imageanalyser.hpp" + lineNumber: 11 + name: "ZShell::ImageAnalyser" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell/ImageAnalyser 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "source" + type: "QString" + read: "source" + write: "setSource" + notify: "sourceChanged" + index: 0 + lineNumber: 15 + } + Property { + name: "sourceItem" + type: "QQuickItem" + isPointer: true + read: "sourceItem" + write: "setSourceItem" + notify: "sourceItemChanged" + index: 1 + lineNumber: 16 + } + Property { + name: "rescaleSize" + type: "int" + read: "rescaleSize" + write: "setRescaleSize" + notify: "rescaleSizeChanged" + index: 2 + lineNumber: 17 + } + Property { + name: "dominantColour" + type: "QColor" + read: "dominantColour" + notify: "dominantColourChanged" + index: 3 + lineNumber: 18 + isReadonly: true + } + Property { + name: "luminance" + type: "double" + read: "luminance" + notify: "luminanceChanged" + index: 4 + lineNumber: 19 + isReadonly: true + } + Signal { name: "sourceChanged"; lineNumber: 39 } + Signal { name: "sourceItemChanged"; lineNumber: 40 } + Signal { name: "rescaleSizeChanged"; lineNumber: 41 } + Signal { name: "dominantColourChanged"; lineNumber: 42 } + Signal { name: "luminanceChanged"; lineNumber: 43 } + Method { name: "requestUpdate"; lineNumber: 36 } + } + Component { + file: "requests.hpp" + lineNumber: 9 + name: "ZShell::Requests" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell/Requests 1.0"] + isCreatable: false + isSingleton: true + exportMetaObjectRevisions: [256] + Method { + name: "get" + isMethodConstant: true + lineNumber: 17 + Parameter { name: "url"; type: "QUrl" } + Parameter { name: "callback"; type: "QJSValue" } + Parameter { name: "onError"; type: "QJSValue" } + } + Method { + name: "get" + isCloned: true + isMethodConstant: true + lineNumber: 17 + Parameter { name: "url"; type: "QUrl" } + Parameter { name: "callback"; type: "QJSValue" } + } + } + Component { + file: "toaster.hpp" + lineNumber: 10 + name: "ZShell::Toast" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell/Toast 1.0"] + isCreatable: false + exportMetaObjectRevisions: [256] + Enum { + name: "Type" + isScoped: true + lineNumber: 23 + values: ["Info", "Success", "Warning", "Error"] + } + Property { + name: "closed" + type: "bool" + read: "closed" + notify: "closedChanged" + index: 0 + lineNumber: 15 + isReadonly: true + } + Property { + name: "title" + type: "QString" + read: "title" + index: 1 + lineNumber: 16 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "message" + type: "QString" + read: "message" + index: 2 + lineNumber: 17 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "icon" + type: "QString" + read: "icon" + index: 3 + lineNumber: 18 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "timeout" + type: "int" + read: "timeout" + index: 4 + lineNumber: 19 + isReadonly: true + isPropertyConstant: true + } + Property { + name: "type" + type: "Type" + read: "type" + index: 5 + lineNumber: 20 + isReadonly: true + isPropertyConstant: true + } + Signal { name: "closedChanged"; lineNumber: 46 } + Signal { name: "finishedClose"; lineNumber: 47 } + Method { name: "close"; lineNumber: 41 } + Method { + name: "lock" + lineNumber: 42 + Parameter { name: "sender"; type: "QObject"; isPointer: true } + } + Method { + name: "unlock" + lineNumber: 43 + Parameter { name: "sender"; type: "QObject"; isPointer: true } + } + } + Component { + file: "toaster.hpp" + lineNumber: 60 + name: "ZShell::Toaster" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell/Toaster 1.0"] + isCreatable: false + isSingleton: true + exportMetaObjectRevisions: [256] + Property { + name: "toasts" + type: "ZShell::Toast" + isList: true + read: "toasts" + notify: "toastsChanged" + index: 0 + lineNumber: 65 + isReadonly: true + } + Signal { name: "toastsChanged"; lineNumber: 76 } + Method { + name: "toast" + lineNumber: 72 + Parameter { name: "title"; type: "QString" } + Parameter { name: "message"; type: "QString" } + Parameter { name: "icon"; type: "QString" } + Parameter { name: "type"; type: "ZShell::Toast::Type" } + Parameter { name: "timeout"; type: "int" } + } + Method { + name: "toast" + isCloned: true + lineNumber: 72 + Parameter { name: "title"; type: "QString" } + Parameter { name: "message"; type: "QString" } + Parameter { name: "icon"; type: "QString" } + Parameter { name: "type"; type: "ZShell::Toast::Type" } + } + Method { + name: "toast" + isCloned: true + lineNumber: 72 + Parameter { name: "title"; type: "QString" } + Parameter { name: "message"; type: "QString" } + Parameter { name: "icon"; type: "QString" } + } + Method { + name: "toast" + isCloned: true + lineNumber: 72 + Parameter { name: "title"; type: "QString" } + Parameter { name: "message"; type: "QString" } + } + } + Component { + file: "writefile.hpp" + lineNumber: 9 + name: "ZShell::ZShellIo" + accessSemantics: "reference" + prototype: "QObject" + exports: ["ZShell/ZShellIo 1.0"] + isCreatable: false + isSingleton: true + exportMetaObjectRevisions: [256] + Method { + name: "saveItem" + lineNumber: 17 + Parameter { name: "target"; type: "QQuickItem"; isPointer: true } + Parameter { name: "path"; type: "QUrl" } + } + Method { + name: "saveItem" + lineNumber: 18 + Parameter { name: "target"; type: "QQuickItem"; isPointer: true } + Parameter { name: "path"; type: "QUrl" } + Parameter { name: "rect"; type: "QRect" } + } + Method { + name: "saveItem" + lineNumber: 19 + Parameter { name: "target"; type: "QQuickItem"; isPointer: true } + Parameter { name: "path"; type: "QUrl" } + Parameter { name: "onSaved"; type: "QJSValue" } + } + Method { + name: "saveItem" + lineNumber: 20 + Parameter { name: "target"; type: "QQuickItem"; isPointer: true } + Parameter { name: "path"; type: "QUrl" } + Parameter { name: "onSaved"; type: "QJSValue" } + Parameter { name: "onFailed"; type: "QJSValue" } + } + Method { + name: "saveItem" + lineNumber: 21 + Parameter { name: "target"; type: "QQuickItem"; isPointer: true } + Parameter { name: "path"; type: "QUrl" } + Parameter { name: "rect"; type: "QRect" } + Parameter { name: "onSaved"; type: "QJSValue" } + } + Method { + name: "saveItem" + lineNumber: 22 + Parameter { name: "target"; type: "QQuickItem"; isPointer: true } + Parameter { name: "path"; type: "QUrl" } + Parameter { name: "rect"; type: "QRect" } + Parameter { name: "onSaved"; type: "QJSValue" } + Parameter { name: "onFailed"; type: "QJSValue" } + } + Method { + name: "copyFile" + type: "bool" + isMethodConstant: true + lineNumber: 25 + Parameter { name: "source"; type: "QUrl" } + Parameter { name: "target"; type: "QUrl" } + Parameter { name: "overwrite"; type: "bool" } + } + Method { + name: "copyFile" + type: "bool" + isCloned: true + isMethodConstant: true + lineNumber: 25 + Parameter { name: "source"; type: "QUrl" } + Parameter { name: "target"; type: "QUrl" } + } + Method { + name: "deleteFile" + type: "bool" + isMethodConstant: true + lineNumber: 26 + Parameter { name: "path"; type: "QUrl" } + } + Method { + name: "toLocalFile" + type: "QString" + isMethodConstant: true + lineNumber: 27 + Parameter { name: "url"; type: "QUrl" } + } + } +} diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/libZShell.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/libZShell.so new file mode 100755 index 0000000..de602c0 Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/libZShell.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/libZShellplugin.so b/pkg/zshell/usr/lib/qt6/qml/ZShell/libZShellplugin.so new file mode 100755 index 0000000..681881c Binary files /dev/null and b/pkg/zshell/usr/lib/qt6/qml/ZShell/libZShellplugin.so differ diff --git a/pkg/zshell/usr/lib/qt6/qml/ZShell/qmldir b/pkg/zshell/usr/lib/qt6/qml/ZShell/qmldir new file mode 100644 index 0000000..747d6b2 --- /dev/null +++ b/pkg/zshell/usr/lib/qt6/qml/ZShell/qmldir @@ -0,0 +1,8 @@ +module ZShell +linktarget ZShellplugin +optional plugin ZShellplugin +classname ZShellPlugin +typeinfo ZShell.qmltypes +prefer :/qt/qml/ZShell/ +depends QtQuick + diff --git a/src/zshell b/src/zshell new file mode 160000 index 0000000..fa63746 --- /dev/null +++ b/src/zshell @@ -0,0 +1 @@ +Subproject commit fa63746dfd723ef6c3b679dbfe21614ed651d0d0 diff --git a/zshell-0.1.0-1-any.pkg.tar.zst b/zshell-0.1.0-1-any.pkg.tar.zst new file mode 100644 index 0000000..9ff9445 Binary files /dev/null and b/zshell-0.1.0-1-any.pkg.tar.zst differ diff --git a/zshell/FETCH_HEAD b/zshell/FETCH_HEAD new file mode 100644 index 0000000..c6b2f0f --- /dev/null +++ b/zshell/FETCH_HEAD @@ -0,0 +1,17 @@ +5cd8014092819d02b65d0f15fef5e71f8078006d not-for-merge branch 'main' of https://github.com/Zacharias-Brohn/z-bar-qt +fa63746dfd723ef6c3b679dbfe21614ed651d0d0 not-for-merge branch 'organize' of https://github.com/Zacharias-Brohn/z-bar-qt +14b6af90f94aa37f69de57f0f8ff34a2074a7c4f not-for-merge branch 'settingsWindow' of https://github.com/Zacharias-Brohn/z-bar-qt +46be1f4648ae002463c277505c0c8121dcfb44cb not-for-merge branch 'testing_removal_hyprland_in_nix_file' of https://github.com/Zacharias-Brohn/z-bar-qt +5ea809581bfc2ddd73818b4b111f56a8a8b6e5e3 not-for-merge 'refs/pull/1/head' of https://github.com/Zacharias-Brohn/z-bar-qt +5cd8014092819d02b65d0f15fef5e71f8078006d not-for-merge 'refs/pull/10/head' of https://github.com/Zacharias-Brohn/z-bar-qt +5cd8014092819d02b65d0f15fef5e71f8078006d not-for-merge 'refs/pull/11/head' of https://github.com/Zacharias-Brohn/z-bar-qt +38932136372ed4e7d7bd1228816d819db9d948e6 not-for-merge 'refs/pull/12/head' of https://github.com/Zacharias-Brohn/z-bar-qt +14b6af90f94aa37f69de57f0f8ff34a2074a7c4f not-for-merge 'refs/pull/13/head' of https://github.com/Zacharias-Brohn/z-bar-qt +ad368a76d60fdec54dc75347245d858657ef9491 not-for-merge 'refs/pull/2/head' of https://github.com/Zacharias-Brohn/z-bar-qt +01a0fa8bae7ed355fec0b36eca5489deb4c20115 not-for-merge 'refs/pull/3/head' of https://github.com/Zacharias-Brohn/z-bar-qt +d82cb4eda65fc4ba2f02b794a27c23b29820f8a0 not-for-merge 'refs/pull/4/head' of https://github.com/Zacharias-Brohn/z-bar-qt +d8199f792a4b4377cde187ac1c7010d50a75db6e not-for-merge 'refs/pull/5/head' of https://github.com/Zacharias-Brohn/z-bar-qt +59369f2adab929d645d411dae6911a3749a9bc57 not-for-merge 'refs/pull/6/head' of https://github.com/Zacharias-Brohn/z-bar-qt +b37fe53fa6d674e6b5889b5081681885155f138f not-for-merge 'refs/pull/7/head' of https://github.com/Zacharias-Brohn/z-bar-qt +6adfa6a9427ca5664114ca177d3384860c6ca14e not-for-merge 'refs/pull/8/head' of https://github.com/Zacharias-Brohn/z-bar-qt +73cf01b3c5c464125d7d152bd6ea2c37b95dc61d not-for-merge 'refs/pull/9/head' of https://github.com/Zacharias-Brohn/z-bar-qt diff --git a/zshell/HEAD b/zshell/HEAD new file mode 100644 index 0000000..b870d82 --- /dev/null +++ b/zshell/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/zshell/config b/zshell/config new file mode 100644 index 0000000..1d8df46 --- /dev/null +++ b/zshell/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true +[remote "origin"] + url = https://github.com/Zacharias-Brohn/z-bar-qt.git + tagOpt = --no-tags + fetch = +refs/*:refs/* + mirror = true diff --git a/zshell/description b/zshell/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/zshell/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/zshell/hooks/applypatch-msg.sample b/zshell/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ b/zshell/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/zshell/hooks/commit-msg.sample b/zshell/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ b/zshell/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/zshell/hooks/fsmonitor-watchman.sample b/zshell/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000..23e856f --- /dev/null +++ b/zshell/hooks/fsmonitor-watchman.sample @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + my $last_update_line = ""; + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + $last_update_line = qq[\n"since": $last_update_token,]; + } + my $query = <<" END"; + ["query", "$git_work_tree", {$last_update_line + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/zshell/hooks/post-update.sample b/zshell/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ b/zshell/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/zshell/hooks/pre-applypatch.sample b/zshell/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ b/zshell/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/zshell/hooks/pre-commit.sample b/zshell/hooks/pre-commit.sample new file mode 100755 index 0000000..29ed5ee --- /dev/null +++ b/zshell/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff-index --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/zshell/hooks/pre-merge-commit.sample b/zshell/hooks/pre-merge-commit.sample new file mode 100755 index 0000000..399eab1 --- /dev/null +++ b/zshell/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/zshell/hooks/pre-push.sample b/zshell/hooks/pre-push.sample new file mode 100755 index 0000000..4ce688d --- /dev/null +++ b/zshell/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/zshell/hooks/pre-rebase.sample b/zshell/hooks/pre-rebase.sample new file mode 100755 index 0000000..6cbef5c --- /dev/null +++ b/zshell/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/zshell/hooks/pre-receive.sample b/zshell/hooks/pre-receive.sample new file mode 100755 index 0000000..a1fd29e --- /dev/null +++ b/zshell/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/zshell/hooks/prepare-commit-msg.sample b/zshell/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..10fa14c --- /dev/null +++ b/zshell/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/zshell/hooks/push-to-checkout.sample b/zshell/hooks/push-to-checkout.sample new file mode 100755 index 0000000..af5a0c0 --- /dev/null +++ b/zshell/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/zshell/hooks/update.sample b/zshell/hooks/update.sample new file mode 100755 index 0000000..c4d426b --- /dev/null +++ b/zshell/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/zshell/info/attributes b/zshell/info/attributes new file mode 100644 index 0000000..1c897b7 --- /dev/null +++ b/zshell/info/attributes @@ -0,0 +1 @@ +* -export-subst -export-ignore diff --git a/zshell/info/exclude b/zshell/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/zshell/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/zshell/objects/04/31f716caba256fc439d394af6f763748453253 b/zshell/objects/04/31f716caba256fc439d394af6f763748453253 new file mode 100644 index 0000000..2b76473 Binary files /dev/null and b/zshell/objects/04/31f716caba256fc439d394af6f763748453253 differ diff --git a/zshell/objects/07/1ffe727cdf632c9fb44c0272214ba4e305ead2 b/zshell/objects/07/1ffe727cdf632c9fb44c0272214ba4e305ead2 new file mode 100644 index 0000000..a1bb9da Binary files /dev/null and b/zshell/objects/07/1ffe727cdf632c9fb44c0272214ba4e305ead2 differ diff --git a/zshell/objects/07/5e886fb228f536e71f617bd73470a5b261f6ad b/zshell/objects/07/5e886fb228f536e71f617bd73470a5b261f6ad new file mode 100644 index 0000000..c6b9fc8 Binary files /dev/null and b/zshell/objects/07/5e886fb228f536e71f617bd73470a5b261f6ad differ diff --git a/zshell/objects/08/6a6ca7122c71c8327ba4ddc76ca0eacf21a7b6 b/zshell/objects/08/6a6ca7122c71c8327ba4ddc76ca0eacf21a7b6 new file mode 100644 index 0000000..f5ded36 Binary files /dev/null and b/zshell/objects/08/6a6ca7122c71c8327ba4ddc76ca0eacf21a7b6 differ diff --git a/zshell/objects/0c/4f0f3f55e80e12018e9ddf69a3eadf4ec5b150 b/zshell/objects/0c/4f0f3f55e80e12018e9ddf69a3eadf4ec5b150 new file mode 100644 index 0000000..00ff444 Binary files /dev/null and b/zshell/objects/0c/4f0f3f55e80e12018e9ddf69a3eadf4ec5b150 differ diff --git a/zshell/objects/0e/7945d7e2114a84627010ebfa07a1c14e621c68 b/zshell/objects/0e/7945d7e2114a84627010ebfa07a1c14e621c68 new file mode 100644 index 0000000..01533de Binary files /dev/null and b/zshell/objects/0e/7945d7e2114a84627010ebfa07a1c14e621c68 differ diff --git a/zshell/objects/0f/f4ffc869e4c688894108e8cac4d6194af40595 b/zshell/objects/0f/f4ffc869e4c688894108e8cac4d6194af40595 new file mode 100644 index 0000000..db3b31e Binary files /dev/null and b/zshell/objects/0f/f4ffc869e4c688894108e8cac4d6194af40595 differ diff --git a/zshell/objects/10/d57290ac41236caff78819d15d93580cca9ab6 b/zshell/objects/10/d57290ac41236caff78819d15d93580cca9ab6 new file mode 100644 index 0000000..ba6f4ff Binary files /dev/null and b/zshell/objects/10/d57290ac41236caff78819d15d93580cca9ab6 differ diff --git a/zshell/objects/11/ca39656bce82e8443f874072349826a3c221d8 b/zshell/objects/11/ca39656bce82e8443f874072349826a3c221d8 new file mode 100644 index 0000000..aea9954 Binary files /dev/null and b/zshell/objects/11/ca39656bce82e8443f874072349826a3c221d8 differ diff --git a/zshell/objects/11/d8f1af3a2fc8fb9233cedc5fca517813710539 b/zshell/objects/11/d8f1af3a2fc8fb9233cedc5fca517813710539 new file mode 100644 index 0000000..16ebc9b Binary files /dev/null and b/zshell/objects/11/d8f1af3a2fc8fb9233cedc5fca517813710539 differ diff --git a/zshell/objects/14/b6af90f94aa37f69de57f0f8ff34a2074a7c4f b/zshell/objects/14/b6af90f94aa37f69de57f0f8ff34a2074a7c4f new file mode 100644 index 0000000..e23a968 Binary files /dev/null and b/zshell/objects/14/b6af90f94aa37f69de57f0f8ff34a2074a7c4f differ diff --git a/zshell/objects/15/f4d8d3a4ca90db59cd2f7b880d43fd92ef589f b/zshell/objects/15/f4d8d3a4ca90db59cd2f7b880d43fd92ef589f new file mode 100644 index 0000000..40a1bec Binary files /dev/null and b/zshell/objects/15/f4d8d3a4ca90db59cd2f7b880d43fd92ef589f differ diff --git a/zshell/objects/15/fc3a89274c0a45fb3bf08e8b09234281632bba b/zshell/objects/15/fc3a89274c0a45fb3bf08e8b09234281632bba new file mode 100644 index 0000000..d91b4d0 Binary files /dev/null and b/zshell/objects/15/fc3a89274c0a45fb3bf08e8b09234281632bba differ diff --git a/zshell/objects/18/78000769842e877c764ff7a674c2f9a6a07a53 b/zshell/objects/18/78000769842e877c764ff7a674c2f9a6a07a53 new file mode 100644 index 0000000..e35f5f6 Binary files /dev/null and b/zshell/objects/18/78000769842e877c764ff7a674c2f9a6a07a53 differ diff --git a/zshell/objects/19/83c76c388e80ff8fc5dbd19fd8d3a7d706ac2e b/zshell/objects/19/83c76c388e80ff8fc5dbd19fd8d3a7d706ac2e new file mode 100644 index 0000000..52d1925 --- /dev/null +++ b/zshell/objects/19/83c76c388e80ff8fc5dbd19fd8d3a7d706ac2e @@ -0,0 +1 @@ +x+)JMU01e040031QN-)K.,I+agYU%Zezlu=q \ No newline at end of file diff --git a/zshell/objects/1c/150e6e01ea60a5b174697dde4049a7c91d84b0 b/zshell/objects/1c/150e6e01ea60a5b174697dde4049a7c91d84b0 new file mode 100644 index 0000000..d97ceb2 Binary files /dev/null and b/zshell/objects/1c/150e6e01ea60a5b174697dde4049a7c91d84b0 differ diff --git a/zshell/objects/21/e36656a5413c33591e58cfcb8e3814265d65a0 b/zshell/objects/21/e36656a5413c33591e58cfcb8e3814265d65a0 new file mode 100644 index 0000000..90c94a5 Binary files /dev/null and b/zshell/objects/21/e36656a5413c33591e58cfcb8e3814265d65a0 differ diff --git a/zshell/objects/22/353eb403fbd5f542e22bad7eb91d9fc6d71bf6 b/zshell/objects/22/353eb403fbd5f542e22bad7eb91d9fc6d71bf6 new file mode 100644 index 0000000..c23ef45 Binary files /dev/null and b/zshell/objects/22/353eb403fbd5f542e22bad7eb91d9fc6d71bf6 differ diff --git a/zshell/objects/25/40a2d69b7ae81db62a6e135cbbfd0677248fec b/zshell/objects/25/40a2d69b7ae81db62a6e135cbbfd0677248fec new file mode 100644 index 0000000..1db5093 Binary files /dev/null and b/zshell/objects/25/40a2d69b7ae81db62a6e135cbbfd0677248fec differ diff --git a/zshell/objects/2a/843a09b75a1271ced50c929ff840ec9bfcffb2 b/zshell/objects/2a/843a09b75a1271ced50c929ff840ec9bfcffb2 new file mode 100644 index 0000000..3384af6 Binary files /dev/null and b/zshell/objects/2a/843a09b75a1271ced50c929ff840ec9bfcffb2 differ diff --git a/zshell/objects/2a/b064c49409e8bee96c0ec867176ae30a0a23c2 b/zshell/objects/2a/b064c49409e8bee96c0ec867176ae30a0a23c2 new file mode 100644 index 0000000..afb059e Binary files /dev/null and b/zshell/objects/2a/b064c49409e8bee96c0ec867176ae30a0a23c2 differ diff --git a/zshell/objects/2c/5691336741b3e441047251c73ce4acbab8d508 b/zshell/objects/2c/5691336741b3e441047251c73ce4acbab8d508 new file mode 100644 index 0000000..75c6e2e Binary files /dev/null and b/zshell/objects/2c/5691336741b3e441047251c73ce4acbab8d508 differ diff --git a/zshell/objects/2c/a419f6a1ee6d33d93f6a26b476e9d8c8d5718a b/zshell/objects/2c/a419f6a1ee6d33d93f6a26b476e9d8c8d5718a new file mode 100644 index 0000000..7cb33de Binary files /dev/null and b/zshell/objects/2c/a419f6a1ee6d33d93f6a26b476e9d8c8d5718a differ diff --git a/zshell/objects/2e/2b0545d7fa97d3c386c13336686e5b041d17d3 b/zshell/objects/2e/2b0545d7fa97d3c386c13336686e5b041d17d3 new file mode 100644 index 0000000..8c92ca0 Binary files /dev/null and b/zshell/objects/2e/2b0545d7fa97d3c386c13336686e5b041d17d3 differ diff --git a/zshell/objects/2e/6866ba1b998e6e9a36de21a0e9f7862f5aa7a8 b/zshell/objects/2e/6866ba1b998e6e9a36de21a0e9f7862f5aa7a8 new file mode 100644 index 0000000..fd8df50 Binary files /dev/null and b/zshell/objects/2e/6866ba1b998e6e9a36de21a0e9f7862f5aa7a8 differ diff --git a/zshell/objects/32/17bd1d7d1371fd2924087f9638a982e90ea8d8 b/zshell/objects/32/17bd1d7d1371fd2924087f9638a982e90ea8d8 new file mode 100644 index 0000000..3f2bbc6 Binary files /dev/null and b/zshell/objects/32/17bd1d7d1371fd2924087f9638a982e90ea8d8 differ diff --git a/zshell/objects/32/18ffe867bbb6f314323e0bb84ae0e0e4e6286c b/zshell/objects/32/18ffe867bbb6f314323e0bb84ae0e0e4e6286c new file mode 100644 index 0000000..1411075 Binary files /dev/null and b/zshell/objects/32/18ffe867bbb6f314323e0bb84ae0e0e4e6286c differ diff --git a/zshell/objects/32/9a269e1be64892ca67b7093858a25fc0d90eab b/zshell/objects/32/9a269e1be64892ca67b7093858a25fc0d90eab new file mode 100644 index 0000000..c548b29 Binary files /dev/null and b/zshell/objects/32/9a269e1be64892ca67b7093858a25fc0d90eab differ diff --git a/zshell/objects/33/423f68c35bc5e55214a1df5c12635a0501ac73 b/zshell/objects/33/423f68c35bc5e55214a1df5c12635a0501ac73 new file mode 100644 index 0000000..beb05f3 Binary files /dev/null and b/zshell/objects/33/423f68c35bc5e55214a1df5c12635a0501ac73 differ diff --git a/zshell/objects/35/b793233b70539fa840a84ecc8b98cbcc9f548d b/zshell/objects/35/b793233b70539fa840a84ecc8b98cbcc9f548d new file mode 100644 index 0000000..5e9d4ae Binary files /dev/null and b/zshell/objects/35/b793233b70539fa840a84ecc8b98cbcc9f548d differ diff --git a/zshell/objects/36/bd3e6dfbdee8d06a602dda4382b6a7e8f542ce b/zshell/objects/36/bd3e6dfbdee8d06a602dda4382b6a7e8f542ce new file mode 100644 index 0000000..f45e844 Binary files /dev/null and b/zshell/objects/36/bd3e6dfbdee8d06a602dda4382b6a7e8f542ce differ diff --git a/zshell/objects/36/bf3bf63462bd60d191507d67d058c6ba12ffee b/zshell/objects/36/bf3bf63462bd60d191507d67d058c6ba12ffee new file mode 100644 index 0000000..79a7908 Binary files /dev/null and b/zshell/objects/36/bf3bf63462bd60d191507d67d058c6ba12ffee differ diff --git a/zshell/objects/38/932136372ed4e7d7bd1228816d819db9d948e6 b/zshell/objects/38/932136372ed4e7d7bd1228816d819db9d948e6 new file mode 100644 index 0000000..37865b1 Binary files /dev/null and b/zshell/objects/38/932136372ed4e7d7bd1228816d819db9d948e6 differ diff --git a/zshell/objects/3e/f696fcb10668820474263ea62763e6d3e11f04 b/zshell/objects/3e/f696fcb10668820474263ea62763e6d3e11f04 new file mode 100644 index 0000000..7af0cad Binary files /dev/null and b/zshell/objects/3e/f696fcb10668820474263ea62763e6d3e11f04 differ diff --git a/zshell/objects/42/7ee50213fdb9abc4ad9567cdc8ae1a97a8fd22 b/zshell/objects/42/7ee50213fdb9abc4ad9567cdc8ae1a97a8fd22 new file mode 100644 index 0000000..5d42cca Binary files /dev/null and b/zshell/objects/42/7ee50213fdb9abc4ad9567cdc8ae1a97a8fd22 differ diff --git a/zshell/objects/45/95d1eb0eae229970496209fde57226b19c637f b/zshell/objects/45/95d1eb0eae229970496209fde57226b19c637f new file mode 100644 index 0000000..f7b59e2 Binary files /dev/null and b/zshell/objects/45/95d1eb0eae229970496209fde57226b19c637f differ diff --git a/zshell/objects/45/f4d6050edcbb6373a7e175b8c653cd5ef82b4f b/zshell/objects/45/f4d6050edcbb6373a7e175b8c653cd5ef82b4f new file mode 100644 index 0000000..e649111 Binary files /dev/null and b/zshell/objects/45/f4d6050edcbb6373a7e175b8c653cd5ef82b4f differ diff --git a/zshell/objects/46/cc993e657b8ffb5a60e07b66701d37eb7582e7 b/zshell/objects/46/cc993e657b8ffb5a60e07b66701d37eb7582e7 new file mode 100644 index 0000000..63e079b Binary files /dev/null and b/zshell/objects/46/cc993e657b8ffb5a60e07b66701d37eb7582e7 differ diff --git a/zshell/objects/49/73b378baf18ed344bc4379689ff4e26b5ebd59 b/zshell/objects/49/73b378baf18ed344bc4379689ff4e26b5ebd59 new file mode 100644 index 0000000..173c962 Binary files /dev/null and b/zshell/objects/49/73b378baf18ed344bc4379689ff4e26b5ebd59 differ diff --git a/zshell/objects/4c/1d272966ce393ac32263963175078b2690ce42 b/zshell/objects/4c/1d272966ce393ac32263963175078b2690ce42 new file mode 100644 index 0000000..81153e9 Binary files /dev/null and b/zshell/objects/4c/1d272966ce393ac32263963175078b2690ce42 differ diff --git a/zshell/objects/4d/888f0feeffe312bf5a5782aff0e21d17385307 b/zshell/objects/4d/888f0feeffe312bf5a5782aff0e21d17385307 new file mode 100644 index 0000000..5659372 Binary files /dev/null and b/zshell/objects/4d/888f0feeffe312bf5a5782aff0e21d17385307 differ diff --git a/zshell/objects/4f/82920af488291aefffa668ab759a5b158ff774 b/zshell/objects/4f/82920af488291aefffa668ab759a5b158ff774 new file mode 100644 index 0000000..b1a68c9 Binary files /dev/null and b/zshell/objects/4f/82920af488291aefffa668ab759a5b158ff774 differ diff --git a/zshell/objects/51/16be397a75284a157df4975d7b5d3c23d9bcb3 b/zshell/objects/51/16be397a75284a157df4975d7b5d3c23d9bcb3 new file mode 100644 index 0000000..8db4533 Binary files /dev/null and b/zshell/objects/51/16be397a75284a157df4975d7b5d3c23d9bcb3 differ diff --git a/zshell/objects/51/9fb77e6c5408aaedf682d02eb24817d2f8725b b/zshell/objects/51/9fb77e6c5408aaedf682d02eb24817d2f8725b new file mode 100644 index 0000000..73020f7 Binary files /dev/null and b/zshell/objects/51/9fb77e6c5408aaedf682d02eb24817d2f8725b differ diff --git a/zshell/objects/54/9c8f6a09fa9685c97ce41a3d980c36b7dc5a1c b/zshell/objects/54/9c8f6a09fa9685c97ce41a3d980c36b7dc5a1c new file mode 100644 index 0000000..fe4711a Binary files /dev/null and b/zshell/objects/54/9c8f6a09fa9685c97ce41a3d980c36b7dc5a1c differ diff --git a/zshell/objects/54/af8d146b2d3f84e70eea916d10477869cf87d9 b/zshell/objects/54/af8d146b2d3f84e70eea916d10477869cf87d9 new file mode 100644 index 0000000..8130783 Binary files /dev/null and b/zshell/objects/54/af8d146b2d3f84e70eea916d10477869cf87d9 differ diff --git a/zshell/objects/55/5f13849e9a9fe9c8b1cfec5251a1bb5b050afa b/zshell/objects/55/5f13849e9a9fe9c8b1cfec5251a1bb5b050afa new file mode 100644 index 0000000..60ec703 --- /dev/null +++ b/zshell/objects/55/5f13849e9a9fe9c8b1cfec5251a1bb5b050afa @@ -0,0 +1 @@ +x+)JMU021d040031QputaQpCMS٧O%ɲ* %96-5j·M7]9 UZ\YP٭VS!ɛR<'պsL 2V9;8(:j`1D>3/-aQlˏZpaNC8t~RVjrI1C{;'7pC[5٩)Ei UOx cc \ No newline at end of file diff --git a/zshell/objects/55/8456a28e15dca9f1d1bf4ac26ba090d88ba855 b/zshell/objects/55/8456a28e15dca9f1d1bf4ac26ba090d88ba855 new file mode 100644 index 0000000..f3fad47 Binary files /dev/null and b/zshell/objects/55/8456a28e15dca9f1d1bf4ac26ba090d88ba855 differ diff --git a/zshell/objects/55/e7dee431043e5fcab2e2e3460a41a7b15738d9 b/zshell/objects/55/e7dee431043e5fcab2e2e3460a41a7b15738d9 new file mode 100644 index 0000000..6faa327 Binary files /dev/null and b/zshell/objects/55/e7dee431043e5fcab2e2e3460a41a7b15738d9 differ diff --git a/zshell/objects/56/694447f990fe5342543c8ecdbb7579b1b3ec07 b/zshell/objects/56/694447f990fe5342543c8ecdbb7579b1b3ec07 new file mode 100644 index 0000000..d848c41 Binary files /dev/null and b/zshell/objects/56/694447f990fe5342543c8ecdbb7579b1b3ec07 differ diff --git a/zshell/objects/58/45020101ff53cbf126c7873987f6c070a7edac b/zshell/objects/58/45020101ff53cbf126c7873987f6c070a7edac new file mode 100644 index 0000000..ab2a8be Binary files /dev/null and b/zshell/objects/58/45020101ff53cbf126c7873987f6c070a7edac differ diff --git a/zshell/objects/58/67fc2dc15e0f6df45d217b5819d07e7185ab26 b/zshell/objects/58/67fc2dc15e0f6df45d217b5819d07e7185ab26 new file mode 100644 index 0000000..077f4ec Binary files /dev/null and b/zshell/objects/58/67fc2dc15e0f6df45d217b5819d07e7185ab26 differ diff --git a/zshell/objects/5c/d8014092819d02b65d0f15fef5e71f8078006d b/zshell/objects/5c/d8014092819d02b65d0f15fef5e71f8078006d new file mode 100644 index 0000000..3f04106 Binary files /dev/null and b/zshell/objects/5c/d8014092819d02b65d0f15fef5e71f8078006d differ diff --git a/zshell/objects/5d/50af91a7e4d5ceae4db702685e14c67a596ad8 b/zshell/objects/5d/50af91a7e4d5ceae4db702685e14c67a596ad8 new file mode 100644 index 0000000..2932dc8 Binary files /dev/null and b/zshell/objects/5d/50af91a7e4d5ceae4db702685e14c67a596ad8 differ diff --git a/zshell/objects/61/e3f61095fcbeb8029bbbba637f796bbbf87585 b/zshell/objects/61/e3f61095fcbeb8029bbbba637f796bbbf87585 new file mode 100644 index 0000000..5b7fb8d Binary files /dev/null and b/zshell/objects/61/e3f61095fcbeb8029bbbba637f796bbbf87585 differ diff --git a/zshell/objects/64/1fef43c85ca00ba2ca30363e3e2342c24788a3 b/zshell/objects/64/1fef43c85ca00ba2ca30363e3e2342c24788a3 new file mode 100644 index 0000000..dc25b39 Binary files /dev/null and b/zshell/objects/64/1fef43c85ca00ba2ca30363e3e2342c24788a3 differ diff --git a/zshell/objects/66/0406f06f77458e2e00519bc88cc02c3c4a2024 b/zshell/objects/66/0406f06f77458e2e00519bc88cc02c3c4a2024 new file mode 100644 index 0000000..32e70bf Binary files /dev/null and b/zshell/objects/66/0406f06f77458e2e00519bc88cc02c3c4a2024 differ diff --git a/zshell/objects/66/c26da1f2e1eecb444d9433564a6795c0ea3979 b/zshell/objects/66/c26da1f2e1eecb444d9433564a6795c0ea3979 new file mode 100644 index 0000000..127d2de Binary files /dev/null and b/zshell/objects/66/c26da1f2e1eecb444d9433564a6795c0ea3979 differ diff --git a/zshell/objects/67/3b53f5cc11409838e846f5fdc16f96172b43b6 b/zshell/objects/67/3b53f5cc11409838e846f5fdc16f96172b43b6 new file mode 100644 index 0000000..8cecafe Binary files /dev/null and b/zshell/objects/67/3b53f5cc11409838e846f5fdc16f96172b43b6 differ diff --git a/zshell/objects/6c/395ced9c9012c53f23fb8ff9e2587659e72af2 b/zshell/objects/6c/395ced9c9012c53f23fb8ff9e2587659e72af2 new file mode 100644 index 0000000..6188cef Binary files /dev/null and b/zshell/objects/6c/395ced9c9012c53f23fb8ff9e2587659e72af2 differ diff --git a/zshell/objects/71/0d4e580dbd63d0a4ff47b3fe20161e532bfb57 b/zshell/objects/71/0d4e580dbd63d0a4ff47b3fe20161e532bfb57 new file mode 100644 index 0000000..9ffbd6f Binary files /dev/null and b/zshell/objects/71/0d4e580dbd63d0a4ff47b3fe20161e532bfb57 differ diff --git a/zshell/objects/72/28f7b3584dbdb8225bc90279eb7a46e2ccc26c b/zshell/objects/72/28f7b3584dbdb8225bc90279eb7a46e2ccc26c new file mode 100644 index 0000000..b014cd6 Binary files /dev/null and b/zshell/objects/72/28f7b3584dbdb8225bc90279eb7a46e2ccc26c differ diff --git a/zshell/objects/72/8b78a69ed4db033fec6e938a4ca9202fb53bb0 b/zshell/objects/72/8b78a69ed4db033fec6e938a4ca9202fb53bb0 new file mode 100644 index 0000000..e6e2a4a Binary files /dev/null and b/zshell/objects/72/8b78a69ed4db033fec6e938a4ca9202fb53bb0 differ diff --git a/zshell/objects/76/fdf649234404e0e56b3194218be463de865c1c b/zshell/objects/76/fdf649234404e0e56b3194218be463de865c1c new file mode 100644 index 0000000..0507622 Binary files /dev/null and b/zshell/objects/76/fdf649234404e0e56b3194218be463de865c1c differ diff --git a/zshell/objects/79/0e79ddbd89fd0bb568a7112ddd445661a24ce1 b/zshell/objects/79/0e79ddbd89fd0bb568a7112ddd445661a24ce1 new file mode 100644 index 0000000..1e6ee79 Binary files /dev/null and b/zshell/objects/79/0e79ddbd89fd0bb568a7112ddd445661a24ce1 differ diff --git a/zshell/objects/7a/922f7612267c5d598d9c37d41bdba9b12dc727 b/zshell/objects/7a/922f7612267c5d598d9c37d41bdba9b12dc727 new file mode 100644 index 0000000..1ab44f2 Binary files /dev/null and b/zshell/objects/7a/922f7612267c5d598d9c37d41bdba9b12dc727 differ diff --git a/zshell/objects/7a/953eafc8ccaf416c77be3b34aab8986373d70f b/zshell/objects/7a/953eafc8ccaf416c77be3b34aab8986373d70f new file mode 100644 index 0000000..e5d82ce Binary files /dev/null and b/zshell/objects/7a/953eafc8ccaf416c77be3b34aab8986373d70f differ diff --git a/zshell/objects/7a/e47ac77064ec8fd1e3ba2c3027e4b0e360115d b/zshell/objects/7a/e47ac77064ec8fd1e3ba2c3027e4b0e360115d new file mode 100644 index 0000000..f806ad7 Binary files /dev/null and b/zshell/objects/7a/e47ac77064ec8fd1e3ba2c3027e4b0e360115d differ diff --git a/zshell/objects/7b/87617922233a30d917b032ea60a9681c01a790 b/zshell/objects/7b/87617922233a30d917b032ea60a9681c01a790 new file mode 100644 index 0000000..644bb2c Binary files /dev/null and b/zshell/objects/7b/87617922233a30d917b032ea60a9681c01a790 differ diff --git a/zshell/objects/7f/cede5f0db96191c60ade9240319f408a067b02 b/zshell/objects/7f/cede5f0db96191c60ade9240319f408a067b02 new file mode 100644 index 0000000..fbbfcd5 Binary files /dev/null and b/zshell/objects/7f/cede5f0db96191c60ade9240319f408a067b02 differ diff --git a/zshell/objects/80/b041cfa931cb42c579522ec0adf88c8c51f9a2 b/zshell/objects/80/b041cfa931cb42c579522ec0adf88c8c51f9a2 new file mode 100644 index 0000000..03e1af9 Binary files /dev/null and b/zshell/objects/80/b041cfa931cb42c579522ec0adf88c8c51f9a2 differ diff --git a/zshell/objects/81/24a524e896ee48168d5c4eb287ef5c6644895d b/zshell/objects/81/24a524e896ee48168d5c4eb287ef5c6644895d new file mode 100644 index 0000000..0d7b927 Binary files /dev/null and b/zshell/objects/81/24a524e896ee48168d5c4eb287ef5c6644895d differ diff --git a/zshell/objects/81/9332239555e78f16ee08036072813697b81bbf b/zshell/objects/81/9332239555e78f16ee08036072813697b81bbf new file mode 100644 index 0000000..f90ee2e Binary files /dev/null and b/zshell/objects/81/9332239555e78f16ee08036072813697b81bbf differ diff --git a/zshell/objects/83/db3a39cb1506beb6089cf1d901132641f27cf6 b/zshell/objects/83/db3a39cb1506beb6089cf1d901132641f27cf6 new file mode 100644 index 0000000..3a6333e Binary files /dev/null and b/zshell/objects/83/db3a39cb1506beb6089cf1d901132641f27cf6 differ diff --git a/zshell/objects/85/94508fe2c6e824ef634d3f8c9ab8c9fc414c97 b/zshell/objects/85/94508fe2c6e824ef634d3f8c9ab8c9fc414c97 new file mode 100644 index 0000000..e42d842 Binary files /dev/null and b/zshell/objects/85/94508fe2c6e824ef634d3f8c9ab8c9fc414c97 differ diff --git a/zshell/objects/86/aec82ea92b37287f7c9213d3b3b3938e51c4bc b/zshell/objects/86/aec82ea92b37287f7c9213d3b3b3938e51c4bc new file mode 100644 index 0000000..4939020 Binary files /dev/null and b/zshell/objects/86/aec82ea92b37287f7c9213d3b3b3938e51c4bc differ diff --git a/zshell/objects/87/40150bd404798c6228162951378d8dea4a7e6c b/zshell/objects/87/40150bd404798c6228162951378d8dea4a7e6c new file mode 100644 index 0000000..e414c78 Binary files /dev/null and b/zshell/objects/87/40150bd404798c6228162951378d8dea4a7e6c differ diff --git a/zshell/objects/87/5f35a4c30402b31c09c49ef298aa7c52788e1c b/zshell/objects/87/5f35a4c30402b31c09c49ef298aa7c52788e1c new file mode 100644 index 0000000..281e5d3 Binary files /dev/null and b/zshell/objects/87/5f35a4c30402b31c09c49ef298aa7c52788e1c differ diff --git a/zshell/objects/8a/5de8b9c9864e23357a58802d822cd586a5fd49 b/zshell/objects/8a/5de8b9c9864e23357a58802d822cd586a5fd49 new file mode 100644 index 0000000..b546d8c Binary files /dev/null and b/zshell/objects/8a/5de8b9c9864e23357a58802d822cd586a5fd49 differ diff --git a/zshell/objects/92/0fc603f5d25f94bfbc13f61764e79df2d740d2 b/zshell/objects/92/0fc603f5d25f94bfbc13f61764e79df2d740d2 new file mode 100644 index 0000000..acfd025 Binary files /dev/null and b/zshell/objects/92/0fc603f5d25f94bfbc13f61764e79df2d740d2 differ diff --git a/zshell/objects/94/4ea84b5a5cf950e57b1b279ed3808c21de6c95 b/zshell/objects/94/4ea84b5a5cf950e57b1b279ed3808c21de6c95 new file mode 100644 index 0000000..ebb728d Binary files /dev/null and b/zshell/objects/94/4ea84b5a5cf950e57b1b279ed3808c21de6c95 differ diff --git a/zshell/objects/96/9aca75230ce53fdc62e7df771c68006fd4776e b/zshell/objects/96/9aca75230ce53fdc62e7df771c68006fd4776e new file mode 100644 index 0000000..cbcc2ee Binary files /dev/null and b/zshell/objects/96/9aca75230ce53fdc62e7df771c68006fd4776e differ diff --git a/zshell/objects/9c/6a9fd3403d0c337015e247ae92aa35e73a47c6 b/zshell/objects/9c/6a9fd3403d0c337015e247ae92aa35e73a47c6 new file mode 100644 index 0000000..c208b3f Binary files /dev/null and b/zshell/objects/9c/6a9fd3403d0c337015e247ae92aa35e73a47c6 differ diff --git a/zshell/objects/9e/5a5638e55974c7c033174f78711fe99250174e b/zshell/objects/9e/5a5638e55974c7c033174f78711fe99250174e new file mode 100644 index 0000000..2be0db7 Binary files /dev/null and b/zshell/objects/9e/5a5638e55974c7c033174f78711fe99250174e differ diff --git a/zshell/objects/9e/76b6679b9399c6ded7977854f95ed2b4ae4b4b b/zshell/objects/9e/76b6679b9399c6ded7977854f95ed2b4ae4b4b new file mode 100644 index 0000000..c116493 Binary files /dev/null and b/zshell/objects/9e/76b6679b9399c6ded7977854f95ed2b4ae4b4b differ diff --git a/zshell/objects/9e/fc9c211bd70ef2f4dcf9912ae65ca22d816810 b/zshell/objects/9e/fc9c211bd70ef2f4dcf9912ae65ca22d816810 new file mode 100644 index 0000000..91241f0 Binary files /dev/null and b/zshell/objects/9e/fc9c211bd70ef2f4dcf9912ae65ca22d816810 differ diff --git a/zshell/objects/a0/9dc91ed7386c7a4d97d42b83682f7cb6421bc3 b/zshell/objects/a0/9dc91ed7386c7a4d97d42b83682f7cb6421bc3 new file mode 100644 index 0000000..468773e Binary files /dev/null and b/zshell/objects/a0/9dc91ed7386c7a4d97d42b83682f7cb6421bc3 differ diff --git a/zshell/objects/a0/dfcfe281e7da8cf1ba5c4848ff0e4bcde11ff9 b/zshell/objects/a0/dfcfe281e7da8cf1ba5c4848ff0e4bcde11ff9 new file mode 100644 index 0000000..8f31fbe Binary files /dev/null and b/zshell/objects/a0/dfcfe281e7da8cf1ba5c4848ff0e4bcde11ff9 differ diff --git a/zshell/objects/a1/5860e917003ca3f496b97aae0c8ff30a14ede2 b/zshell/objects/a1/5860e917003ca3f496b97aae0c8ff30a14ede2 new file mode 100644 index 0000000..aab17cb Binary files /dev/null and b/zshell/objects/a1/5860e917003ca3f496b97aae0c8ff30a14ede2 differ diff --git a/zshell/objects/a1/d1ca1d98905f11533f279ee746406b33498cfb b/zshell/objects/a1/d1ca1d98905f11533f279ee746406b33498cfb new file mode 100644 index 0000000..25badc7 Binary files /dev/null and b/zshell/objects/a1/d1ca1d98905f11533f279ee746406b33498cfb differ diff --git a/zshell/objects/a5/06a3b038bebc25c26fd71f26e2518c0d657d18 b/zshell/objects/a5/06a3b038bebc25c26fd71f26e2518c0d657d18 new file mode 100644 index 0000000..2b60d5d Binary files /dev/null and b/zshell/objects/a5/06a3b038bebc25c26fd71f26e2518c0d657d18 differ diff --git a/zshell/objects/a5/b080afc6d3c5fa69b5de0ef99c8be0aed001d3 b/zshell/objects/a5/b080afc6d3c5fa69b5de0ef99c8be0aed001d3 new file mode 100644 index 0000000..fd98edd Binary files /dev/null and b/zshell/objects/a5/b080afc6d3c5fa69b5de0ef99c8be0aed001d3 differ diff --git a/zshell/objects/a9/20cc105f87f7405868650cd7bca1bfd79e92e0 b/zshell/objects/a9/20cc105f87f7405868650cd7bca1bfd79e92e0 new file mode 100644 index 0000000..fb58a42 Binary files /dev/null and b/zshell/objects/a9/20cc105f87f7405868650cd7bca1bfd79e92e0 differ diff --git a/zshell/objects/a9/7b26b85b985af77ee831d93c1f0e847900d7e5 b/zshell/objects/a9/7b26b85b985af77ee831d93c1f0e847900d7e5 new file mode 100644 index 0000000..4c82290 Binary files /dev/null and b/zshell/objects/a9/7b26b85b985af77ee831d93c1f0e847900d7e5 differ diff --git a/zshell/objects/ae/52744e0bdb36cd60a896971b4133aea316c3e5 b/zshell/objects/ae/52744e0bdb36cd60a896971b4133aea316c3e5 new file mode 100644 index 0000000..36fb7fe Binary files /dev/null and b/zshell/objects/ae/52744e0bdb36cd60a896971b4133aea316c3e5 differ diff --git a/zshell/objects/b0/20a1eafea8390b522f033cb11194c60a5ac32b b/zshell/objects/b0/20a1eafea8390b522f033cb11194c60a5ac32b new file mode 100644 index 0000000..fc3330c Binary files /dev/null and b/zshell/objects/b0/20a1eafea8390b522f033cb11194c60a5ac32b differ diff --git a/zshell/objects/b4/92d16be44cd9e84cd255bf8e153811e7cf9302 b/zshell/objects/b4/92d16be44cd9e84cd255bf8e153811e7cf9302 new file mode 100644 index 0000000..88cbaf1 Binary files /dev/null and b/zshell/objects/b4/92d16be44cd9e84cd255bf8e153811e7cf9302 differ diff --git a/zshell/objects/b8/555c2c26b8dfd449d38ff2274f58117b982357 b/zshell/objects/b8/555c2c26b8dfd449d38ff2274f58117b982357 new file mode 100644 index 0000000..7e62347 Binary files /dev/null and b/zshell/objects/b8/555c2c26b8dfd449d38ff2274f58117b982357 differ diff --git a/zshell/objects/b8/a52ea3a508830ab55f79268aec77bf57324cf0 b/zshell/objects/b8/a52ea3a508830ab55f79268aec77bf57324cf0 new file mode 100644 index 0000000..d7ded70 Binary files /dev/null and b/zshell/objects/b8/a52ea3a508830ab55f79268aec77bf57324cf0 differ diff --git a/zshell/objects/be/89dbf0d650f2e75d4f327c3fba704a44dbda80 b/zshell/objects/be/89dbf0d650f2e75d4f327c3fba704a44dbda80 new file mode 100644 index 0000000..50437a5 Binary files /dev/null and b/zshell/objects/be/89dbf0d650f2e75d4f327c3fba704a44dbda80 differ diff --git a/zshell/objects/bf/e7549e9425d3964ce0b110b3ccac7eaca7202d b/zshell/objects/bf/e7549e9425d3964ce0b110b3ccac7eaca7202d new file mode 100644 index 0000000..5277a6b Binary files /dev/null and b/zshell/objects/bf/e7549e9425d3964ce0b110b3ccac7eaca7202d differ diff --git a/zshell/objects/c0/21d826e8c7ca9bd7a1e3309d5c31d25d105641 b/zshell/objects/c0/21d826e8c7ca9bd7a1e3309d5c31d25d105641 new file mode 100644 index 0000000..e07ada2 Binary files /dev/null and b/zshell/objects/c0/21d826e8c7ca9bd7a1e3309d5c31d25d105641 differ diff --git a/zshell/objects/c5/f2a6b5ca1bd9a80f1b2e4f7ea937e3f5a325b9 b/zshell/objects/c5/f2a6b5ca1bd9a80f1b2e4f7ea937e3f5a325b9 new file mode 100644 index 0000000..e88e5ab Binary files /dev/null and b/zshell/objects/c5/f2a6b5ca1bd9a80f1b2e4f7ea937e3f5a325b9 differ diff --git a/zshell/objects/c6/5d3aa82cab9744b6bc38fc10d48e86c11ceaee b/zshell/objects/c6/5d3aa82cab9744b6bc38fc10d48e86c11ceaee new file mode 100644 index 0000000..d0051fb Binary files /dev/null and b/zshell/objects/c6/5d3aa82cab9744b6bc38fc10d48e86c11ceaee differ diff --git a/zshell/objects/ca/7875197ef48a914c87103242c56ddd72427849 b/zshell/objects/ca/7875197ef48a914c87103242c56ddd72427849 new file mode 100644 index 0000000..0021164 Binary files /dev/null and b/zshell/objects/ca/7875197ef48a914c87103242c56ddd72427849 differ diff --git a/zshell/objects/cb/c124a6bc14c9a42d183d25e62f79bfdf8b2339 b/zshell/objects/cb/c124a6bc14c9a42d183d25e62f79bfdf8b2339 new file mode 100644 index 0000000..76cf820 Binary files /dev/null and b/zshell/objects/cb/c124a6bc14c9a42d183d25e62f79bfdf8b2339 differ diff --git a/zshell/objects/cc/605c6fecdc4b263bb46db076cec8039ab1addf b/zshell/objects/cc/605c6fecdc4b263bb46db076cec8039ab1addf new file mode 100644 index 0000000..3d5ad60 Binary files /dev/null and b/zshell/objects/cc/605c6fecdc4b263bb46db076cec8039ab1addf differ diff --git a/zshell/objects/cd/efe3706f6ee23bb67d952d3411a4fedd95a7d3 b/zshell/objects/cd/efe3706f6ee23bb67d952d3411a4fedd95a7d3 new file mode 100644 index 0000000..347969c Binary files /dev/null and b/zshell/objects/cd/efe3706f6ee23bb67d952d3411a4fedd95a7d3 differ diff --git a/zshell/objects/ce/f105f95a2b257afaed4d7ab75de52c5471ce01 b/zshell/objects/ce/f105f95a2b257afaed4d7ab75de52c5471ce01 new file mode 100644 index 0000000..60be99e Binary files /dev/null and b/zshell/objects/ce/f105f95a2b257afaed4d7ab75de52c5471ce01 differ diff --git a/zshell/objects/d1/68e2f350ab9ed42a4eca480107bdfa4c6a6755 b/zshell/objects/d1/68e2f350ab9ed42a4eca480107bdfa4c6a6755 new file mode 100644 index 0000000..b028585 Binary files /dev/null and b/zshell/objects/d1/68e2f350ab9ed42a4eca480107bdfa4c6a6755 differ diff --git a/zshell/objects/d4/d382141147156e73790d6b510e8513a3dfb921 b/zshell/objects/d4/d382141147156e73790d6b510e8513a3dfb921 new file mode 100644 index 0000000..0fa7698 Binary files /dev/null and b/zshell/objects/d4/d382141147156e73790d6b510e8513a3dfb921 differ diff --git a/zshell/objects/de/e783df77ca50c71643ac7ec77ee53f8d8446c0 b/zshell/objects/de/e783df77ca50c71643ac7ec77ee53f8d8446c0 new file mode 100644 index 0000000..8201b49 Binary files /dev/null and b/zshell/objects/de/e783df77ca50c71643ac7ec77ee53f8d8446c0 differ diff --git a/zshell/objects/e1/a6e9d0c94bf2aa08216d3161eefe48e958d926 b/zshell/objects/e1/a6e9d0c94bf2aa08216d3161eefe48e958d926 new file mode 100644 index 0000000..ae9dd59 Binary files /dev/null and b/zshell/objects/e1/a6e9d0c94bf2aa08216d3161eefe48e958d926 differ diff --git a/zshell/objects/e3/b4abc8b7ba5a096e230d53c02d4c1e8e897e26 b/zshell/objects/e3/b4abc8b7ba5a096e230d53c02d4c1e8e897e26 new file mode 100644 index 0000000..f592650 Binary files /dev/null and b/zshell/objects/e3/b4abc8b7ba5a096e230d53c02d4c1e8e897e26 differ diff --git a/zshell/objects/e6/0d8ccff88da06a2c645f7644ec4268d74adc9f b/zshell/objects/e6/0d8ccff88da06a2c645f7644ec4268d74adc9f new file mode 100644 index 0000000..ebe3dbc Binary files /dev/null and b/zshell/objects/e6/0d8ccff88da06a2c645f7644ec4268d74adc9f differ diff --git a/zshell/objects/e8/0e635db5eacad0b9f386905a51b061d1fe98fd b/zshell/objects/e8/0e635db5eacad0b9f386905a51b061d1fe98fd new file mode 100644 index 0000000..93bc3e7 Binary files /dev/null and b/zshell/objects/e8/0e635db5eacad0b9f386905a51b061d1fe98fd differ diff --git a/zshell/objects/e8/cb3ea1f7bfce7655ef364645eaa51ac960d49a b/zshell/objects/e8/cb3ea1f7bfce7655ef364645eaa51ac960d49a new file mode 100644 index 0000000..08d03a7 Binary files /dev/null and b/zshell/objects/e8/cb3ea1f7bfce7655ef364645eaa51ac960d49a differ diff --git a/zshell/objects/e8/e294b0860a391df1642b6e4c5a876cf74291ae b/zshell/objects/e8/e294b0860a391df1642b6e4c5a876cf74291ae new file mode 100644 index 0000000..b1c8022 Binary files /dev/null and b/zshell/objects/e8/e294b0860a391df1642b6e4c5a876cf74291ae differ diff --git a/zshell/objects/ed/50ca90e7679eaa44fb5165a6cae57a63d55a42 b/zshell/objects/ed/50ca90e7679eaa44fb5165a6cae57a63d55a42 new file mode 100644 index 0000000..2b15259 Binary files /dev/null and b/zshell/objects/ed/50ca90e7679eaa44fb5165a6cae57a63d55a42 differ diff --git a/zshell/objects/ef/6d5310b03033c1597cac4f27cd53095413f090 b/zshell/objects/ef/6d5310b03033c1597cac4f27cd53095413f090 new file mode 100644 index 0000000..9381406 Binary files /dev/null and b/zshell/objects/ef/6d5310b03033c1597cac4f27cd53095413f090 differ diff --git a/zshell/objects/f4/61a2bfb991255d106f0704a421df03cb7944da b/zshell/objects/f4/61a2bfb991255d106f0704a421df03cb7944da new file mode 100644 index 0000000..6a1db5f Binary files /dev/null and b/zshell/objects/f4/61a2bfb991255d106f0704a421df03cb7944da differ diff --git a/zshell/objects/f4/72c86550cf8d2268d5b8fb7bc6471ab4562c13 b/zshell/objects/f4/72c86550cf8d2268d5b8fb7bc6471ab4562c13 new file mode 100644 index 0000000..fb9d8e5 Binary files /dev/null and b/zshell/objects/f4/72c86550cf8d2268d5b8fb7bc6471ab4562c13 differ diff --git a/zshell/objects/f5/c3e1b28574df330074cd7507318e2551839b13 b/zshell/objects/f5/c3e1b28574df330074cd7507318e2551839b13 new file mode 100644 index 0000000..e3de9f0 Binary files /dev/null and b/zshell/objects/f5/c3e1b28574df330074cd7507318e2551839b13 differ diff --git a/zshell/objects/f6/984c4615d4eb1a0a6cd1de640199218246b685 b/zshell/objects/f6/984c4615d4eb1a0a6cd1de640199218246b685 new file mode 100644 index 0000000..c3f7682 --- /dev/null +++ b/zshell/objects/f6/984c4615d4eb1a0a6cd1de640199218246b685 @@ -0,0 +1,2 @@ +x+)JMU042f040031Qp,(HM,JKN+am ['zgNje/p{E(TSbrvzQ~i^ +XOֲg9'!qK>yvJԼԢ)Pyk3k?>5* \ No newline at end of file diff --git a/zshell/objects/f7/29481ab0a43fb79ba5c4b6819c5609c7ef579c b/zshell/objects/f7/29481ab0a43fb79ba5c4b6819c5609c7ef579c new file mode 100644 index 0000000..29aaf4d Binary files /dev/null and b/zshell/objects/f7/29481ab0a43fb79ba5c4b6819c5609c7ef579c differ diff --git a/zshell/objects/f8/eb115c34af983dd2dbdbde91a5a485fe26d91c b/zshell/objects/f8/eb115c34af983dd2dbdbde91a5a485fe26d91c new file mode 100644 index 0000000..eadd8c7 Binary files /dev/null and b/zshell/objects/f8/eb115c34af983dd2dbdbde91a5a485fe26d91c differ diff --git a/zshell/objects/f9/05769905cdbcccc35e181958da1f63ba0010b7 b/zshell/objects/f9/05769905cdbcccc35e181958da1f63ba0010b7 new file mode 100644 index 0000000..35631b9 Binary files /dev/null and b/zshell/objects/f9/05769905cdbcccc35e181958da1f63ba0010b7 differ diff --git a/zshell/objects/fa/63746dfd723ef6c3b679dbfe21614ed651d0d0 b/zshell/objects/fa/63746dfd723ef6c3b679dbfe21614ed651d0d0 new file mode 100644 index 0000000..23af288 Binary files /dev/null and b/zshell/objects/fa/63746dfd723ef6c3b679dbfe21614ed651d0d0 differ diff --git a/zshell/objects/fe/3d77c68575394b5ff4f8bba9ae0d9317b66063 b/zshell/objects/fe/3d77c68575394b5ff4f8bba9ae0d9317b66063 new file mode 100644 index 0000000..7f3e3bb Binary files /dev/null and b/zshell/objects/fe/3d77c68575394b5ff4f8bba9ae0d9317b66063 differ diff --git a/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.idx b/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.idx new file mode 100644 index 0000000..8b7bfcc Binary files /dev/null and b/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.idx differ diff --git a/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.pack b/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.pack new file mode 100644 index 0000000..75fbaba Binary files /dev/null and b/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.pack differ diff --git a/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.rev b/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.rev new file mode 100644 index 0000000..d97aab6 Binary files /dev/null and b/zshell/objects/pack/pack-3d9e0578f927e78d1e43c670f5bd98a9fc84ec33.rev differ diff --git a/zshell/packed-refs b/zshell/packed-refs new file mode 100644 index 0000000..e009594 --- /dev/null +++ b/zshell/packed-refs @@ -0,0 +1,12 @@ +# pack-refs with: peeled fully-peeled sorted +b3bb593b54129022a642c8497752a437a8fa780c refs/heads/main +46be1f4648ae002463c277505c0c8121dcfb44cb refs/heads/testing_removal_hyprland_in_nix_file +5ea809581bfc2ddd73818b4b111f56a8a8b6e5e3 refs/pull/1/head +ad368a76d60fdec54dc75347245d858657ef9491 refs/pull/2/head +01a0fa8bae7ed355fec0b36eca5489deb4c20115 refs/pull/3/head +d82cb4eda65fc4ba2f02b794a27c23b29820f8a0 refs/pull/4/head +d8199f792a4b4377cde187ac1c7010d50a75db6e refs/pull/5/head +59369f2adab929d645d411dae6911a3749a9bc57 refs/pull/6/head +b37fe53fa6d674e6b5889b5081681885155f138f refs/pull/7/head +6adfa6a9427ca5664114ca177d3384860c6ca14e refs/pull/8/head +73cf01b3c5c464125d7d152bd6ea2c37b95dc61d refs/pull/9/head diff --git a/zshell/refs/heads/main b/zshell/refs/heads/main new file mode 100644 index 0000000..a31c924 --- /dev/null +++ b/zshell/refs/heads/main @@ -0,0 +1 @@ +5cd8014092819d02b65d0f15fef5e71f8078006d diff --git a/zshell/refs/heads/organize b/zshell/refs/heads/organize new file mode 100644 index 0000000..790dd21 --- /dev/null +++ b/zshell/refs/heads/organize @@ -0,0 +1 @@ +fa63746dfd723ef6c3b679dbfe21614ed651d0d0 diff --git a/zshell/refs/heads/settingsWindow b/zshell/refs/heads/settingsWindow new file mode 100644 index 0000000..3eb18f4 --- /dev/null +++ b/zshell/refs/heads/settingsWindow @@ -0,0 +1 @@ +14b6af90f94aa37f69de57f0f8ff34a2074a7c4f diff --git a/zshell/refs/pull/10/head b/zshell/refs/pull/10/head new file mode 100644 index 0000000..a31c924 --- /dev/null +++ b/zshell/refs/pull/10/head @@ -0,0 +1 @@ +5cd8014092819d02b65d0f15fef5e71f8078006d diff --git a/zshell/refs/pull/11/head b/zshell/refs/pull/11/head new file mode 100644 index 0000000..a31c924 --- /dev/null +++ b/zshell/refs/pull/11/head @@ -0,0 +1 @@ +5cd8014092819d02b65d0f15fef5e71f8078006d diff --git a/zshell/refs/pull/12/head b/zshell/refs/pull/12/head new file mode 100644 index 0000000..6509f94 --- /dev/null +++ b/zshell/refs/pull/12/head @@ -0,0 +1 @@ +38932136372ed4e7d7bd1228816d819db9d948e6 diff --git a/zshell/refs/pull/13/head b/zshell/refs/pull/13/head new file mode 100644 index 0000000..3eb18f4 --- /dev/null +++ b/zshell/refs/pull/13/head @@ -0,0 +1 @@ +14b6af90f94aa37f69de57f0f8ff34a2074a7c4f