diff --git a/CMakeLists.txt b/CMakeLists.txt index bc89f44..302c0df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(ENABLE_MODULES "plugin" CACHE STRING "Modules to build/install") +set(ENABLE_MODULES "plugin;shell" CACHE STRING "Modules to build/install") set(INSTALL_LIBDIR "usr/lib/ZShell" CACHE STRING "Library install dir") set(INSTALL_QMLDIR "usr/lib/qt6/qml" CACHE STRING "QML install dir") +set(INSTALL_QSCONFDIR "etc/xdg/quickshell/zshell" CACHE STRING "Quickshell config install dir") add_compile_options( -Wall -Wextra -Wpedantic -Wshadow -Wconversion diff --git a/Helpers/Wallpapers.qml b/Helpers/Wallpapers.qml index 393fb4d..a37e9df 100644 --- a/Helpers/Wallpapers.qml +++ b/Helpers/Wallpapers.qml @@ -41,6 +41,14 @@ Searcher { forward: false }) + IpcHandler { + target: "wallpaper" + + function set(path: string): void { + root.setWallpaper(path); + } + } + FileSystemModel { id: wallpapers diff --git a/Modules/Lock/Lock.qml b/Modules/Lock/Lock.qml index 90b6358..54b41a4 100644 --- a/Modules/Lock/Lock.qml +++ b/Modules/Lock/Lock.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import Quickshell import Quickshell.Wayland import Quickshell.Hyprland +import Quickshell.Io import QtQuick import QtQuick.Effects import qs.Components @@ -33,6 +34,14 @@ Scope { lock: lock } + IpcHandler { + target: "lock" + + function lock() { + return lock.locked = true; + } + } + CustomShortcut { name: "lock" description: "Lock the current session" diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..16b02ca --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,29 @@ +pkgname='zshell' +pkgver=0.1.0 +pkgrel=1 +pkgdesc='The cli for zshell' +arch=('any') +url='https://github.com/Zacharias-Brohn/z-bar-qt' +license=('GPL-3.0-only') +depends=('python' 'python-pillow' 'python-materialyoucolor' 'libnotify' 'swappy' 'dart-sass' + 'app2unit' 'wl-clipboard' 'dconf' 'cliphist') +makedepends=('python-build' 'python-installer' 'python-hatch' 'python-hatch-vcs') +source=("$pkgname::git+$url.git") +sha256sums=('SKIP') + +build() { + cd "${srcdir}/${pkgname}/cli" + python -m build --wheel --no-isolation + + cd .. + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/ + cmake --build build +} + +package() { + cd "${srcdir}/${pkgname}/cli" + python -m installer --destdir="$pkgdir" dist/*.whl + + cd .. + DESTDIR="$pkgdir" cmake --install build +} diff --git a/cli/bin/zshell b/cli/bin/zshell new file mode 100755 index 0000000..cf03348 --- /dev/null +++ b/cli/bin/zshell @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +cd "$(dirname $0)/../src" || exit + +python3 -m zshell "$@" diff --git a/cli/dist/zshell-0.1.0-py3-none-any.whl b/cli/dist/zshell-0.1.0-py3-none-any.whl new file mode 100644 index 0000000..99281d0 Binary files /dev/null and b/cli/dist/zshell-0.1.0-py3-none-any.whl differ diff --git a/cli/pyproject.toml b/cli/pyproject.toml new file mode 100644 index 0000000..a234745 --- /dev/null +++ b/cli/pyproject.toml @@ -0,0 +1,27 @@ +[build-system] +requires = ["hatchling >= 1.26"] +build-backend = "hatchling.build" + +[project] +name = "zshell" +requires-python = ">=3.13" +version = "0.1.0" +dependencies = [ + "typer", + "pillow", + "materialyoucolor" +] + +[project.scripts] +zshell-cli = "zshell:main" + +[tool.hatch.version] +source = "vcs" + +[tool.hatch.build.targets.sdist] +only-include = [ + "src", +] + +[tool.ruff] +line-length = 120 diff --git a/cli/src/zshell/__init__.py b/cli/src/zshell/__init__.py new file mode 100644 index 0000000..2dee338 --- /dev/null +++ b/cli/src/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/cli/src/zshell/__main__.py b/cli/src/zshell/__main__.py new file mode 100644 index 0000000..868d99e --- /dev/null +++ b/cli/src/zshell/__main__.py @@ -0,0 +1,4 @@ +from . import main + +if __name__ == "__main__": + main() diff --git a/cli/src/zshell/__pycache__/__init__.cpython-313.pyc b/cli/src/zshell/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..3bf89ad Binary files /dev/null and b/cli/src/zshell/__pycache__/__init__.cpython-313.pyc differ diff --git a/cli/src/zshell/__pycache__/__init__.cpython-314.pyc b/cli/src/zshell/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..d26b5cb Binary files /dev/null and b/cli/src/zshell/__pycache__/__init__.cpython-314.pyc differ diff --git a/cli/src/zshell/__pycache__/__main__.cpython-314.pyc b/cli/src/zshell/__pycache__/__main__.cpython-314.pyc new file mode 100644 index 0000000..bb3ed33 Binary files /dev/null and b/cli/src/zshell/__pycache__/__main__.cpython-314.pyc differ diff --git a/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc new file mode 100644 index 0000000..7d0c345 Binary files /dev/null and b/cli/src/zshell/subcommands/__pycache__/scheme.cpython-313.pyc differ diff --git a/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc new file mode 100644 index 0000000..043fc1d Binary files /dev/null and b/cli/src/zshell/subcommands/__pycache__/screenshot.cpython-313.pyc differ diff --git a/cli/src/zshell/subcommands/__pycache__/shell.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/shell.cpython-313.pyc new file mode 100644 index 0000000..b611f82 Binary files /dev/null and b/cli/src/zshell/subcommands/__pycache__/shell.cpython-313.pyc differ diff --git a/cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-313.pyc b/cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-313.pyc new file mode 100644 index 0000000..fe1b0a8 Binary files /dev/null and b/cli/src/zshell/subcommands/__pycache__/wallpaper.cpython-313.pyc differ diff --git a/cli/src/zshell/subcommands/scheme.py b/cli/src/zshell/subcommands/scheme.py new file mode 100644 index 0000000..3ab34dd --- /dev/null +++ b/cli/src/zshell/subcommands/scheme.py @@ -0,0 +1,113 @@ +from typing import Annotated +import typer +import json + +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( + path: Annotated[ + Path, + typer.Option(), + ], + output: Annotated[ + Path, + typer.Option(), + ], + thumbnail: Annotated[ + Path, + typer.Option(), + ], + scheme: Annotated[ + str, + typer.Option() + ] +): + 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 generate_color_scheme(thumbnail_path, output_path): + image = Image.open(thumbnail_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) + score = Score.score(result)[0] + + scheme = Scheme( + Hct.from_int(score), + True, + 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) + + output_dict = { + "name": "dynamic", + "flavour": "default", + "mode": "dark", + "variant": "tonalspot", + "colors": color_dict + } + + output_file = Path(output_path) + output_file.parent.mkdir(parents=True, exist_ok=True) + + with open(output_file, "w") as f: + json.dump(output_dict, f, indent=4) + + def int_to_hex(argb_int): + return "#{:06X}".format(argb_int & 0xFFFFFF) + + try: + generate_thumbnail(path, str(thumbnail)) + generate_color_scheme(str(thumbnail), output) + except Exception as e: + print(f"Error: {e}") + with open(output, "w") as f: + f.write(f"Error: {e}") diff --git a/cli/src/zshell/subcommands/screenshot.py b/cli/src/zshell/subcommands/screenshot.py new file mode 100644 index 0000000..8edcb7f --- /dev/null +++ b/cli/src/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/cli/src/zshell/subcommands/shell.py b/cli/src/zshell/subcommands/shell.py new file mode 100644 index 0000000..c503891 --- /dev/null +++ b/cli/src/zshell/subcommands/shell.py @@ -0,0 +1,26 @@ +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 + ([] 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) diff --git a/cli/src/zshell/subcommands/wallpaper.py b/cli/src/zshell/subcommands/wallpaper.py new file mode 100644 index 0000000..42256c6 --- /dev/null +++ b/cli/src/zshell/subcommands/wallpaper.py @@ -0,0 +1,14 @@ +import subprocess +import typer + +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) diff --git a/plans/ideas.md b/plans/ideas.md index 988133c..125f1c0 100644 --- a/plans/ideas.md +++ b/plans/ideas.md @@ -7,5 +7,5 @@ - [ ] Quick toggle for BT, WiFi (modules in the tray do this too) - [x] Auto hide unless on mouse hover. Also implement bar changes to mute/volume to show notif or show bar for a couple seconds. - [x] Maybe already possible; have keybinds to show certain menus. I do not want to touch my mouse to see notifications for example. Not everything in the bar needs this, but some would be good to have. -- [ ] Pressing ESC or some obvious button to close nc. +- [x] Pressing ESC or some obvious button to close nc. - [x] Another branch for development, hold off big changes so that a working bar or if there are big config changes.