[SCRIPT] Updated

This commit is contained in:
t
2025-03-31 20:14:11 +02:00
parent 810f54cb65
commit 314a27eb42
472 changed files with 11721 additions and 921 deletions
@@ -0,0 +1,3 @@
from .service import MaterialService
__all__ = ["MaterialService"]
@@ -0,0 +1,11 @@
import os
import ignis
from ignis.utils import Utils
MATERIAL_CACHE_DIR = f"{ignis.CACHE_DIR}/material" # type: ignore
TEMPLATES = Utils.get_current_dir() + "/templates"
SAMPLE_WALL = Utils.get_current_dir() + "/sample_wall.png"
os.makedirs(MATERIAL_CACHE_DIR, exist_ok=True)
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

@@ -0,0 +1,144 @@
#!/usr/bin/python
import os
from jinja2 import Template
from PIL import Image
from materialyoucolor.quantize import QuantizeCelebi
from materialyoucolor.hct import Hct
from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot
from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors
from materialyoucolor.score.score import Score
from ignis.utils import Utils
from ignis.app import IgnisApp
from ignis.base_service import BaseService
from ignis.services.wallpaper import CACHE_WALLPAPER_PATH
from gi.repository import GObject # type: ignore
from ignis.services.wallpaper import WallpaperService
from ignis.services.options import OptionsService
from .constants import MATERIAL_CACHE_DIR, TEMPLATES, SAMPLE_WALL
from .util import rgba_to_hex, calculate_optimal_size
app = IgnisApp.get_default()
class MaterialService(BaseService):
def __init__(self):
super().__init__()
self._wallpaper = WallpaperService.get_default()
options = OptionsService.get_default()
opt_group = options.create_group(name="material", exists_ok=True)
self._dark_mode_opt = opt_group.create_option(
name="dark_mode", default=True, exists_ok=True
)
self._colors_opt = opt_group.create_option(
name="colors", default={}, exists_ok=True
)
if not os.path.exists(CACHE_WALLPAPER_PATH):
self.__on_colors_not_found()
if self.colors == {}:
self.__on_colors_not_found()
@GObject.Property
def dark_mode(self) -> bool:
return self._dark_mode_opt.value
@dark_mode.setter
def dark_mode(self, value: bool) -> None:
self._dark_mode_opt.value = value
self.generate_colors(CACHE_WALLPAPER_PATH)
@GObject.Property
def colors(self) -> dict:
return self._colors_opt.value
def __on_colors_not_found(self) -> None:
self._wallpaper.set_wallpaper(SAMPLE_WALL)
self.generate_colors(SAMPLE_WALL)
Utils.exec_sh_async("hyprctl reload")
def get_colors_from_img(self, path: str, dark_mode: bool) -> dict[str, str]:
image = Image.open(path)
wsize, hsize = image.size
wsize_new, hsize_new = calculate_optimal_size(wsize, hsize, 128)
if wsize_new < wsize or hsize_new < hsize:
image = image.resize((wsize_new, hsize_new), Image.Resampling.BICUBIC) # type: ignore
pixel_len = image.width * image.height
image_data = image.getdata()
pixel_array = [image_data[_] for _ in range(0, pixel_len, 1)]
colors = QuantizeCelebi(pixel_array, 128)
argb = Score.score(colors)[0]
hct = Hct.from_int(argb)
scheme = SchemeTonalSpot(hct, dark_mode, 0.0)
material_colors = {}
for color in vars(MaterialDynamicColors).keys():
color_name = getattr(MaterialDynamicColors, color)
if hasattr(color_name, "get_hct"):
rgba = color_name.get_hct(scheme).to_rgba()
material_colors[color] = rgba_to_hex(rgba)
return material_colors
def generate_colors(self, path: str) -> None:
colors = self.get_colors_from_img(path, self.dark_mode)
dark_colors = self.get_colors_from_img(path, True)
self._colors_opt.value = colors
self.__render_templates(colors, dark_colors)
self.__setup(path)
def __render_templates(self, colors: dict, dark_colors: dict) -> None:
for template in os.listdir(TEMPLATES):
self.render_template(
colors=colors,
dark_mode=self.dark_mode,
input_file=f"{TEMPLATES}/{template}",
output_file=f"{MATERIAL_CACHE_DIR}/{template}",
)
for template in os.listdir(TEMPLATES):
self.render_template(
colors=dark_colors,
dark_mode=True,
input_file=f"{TEMPLATES}/{template}",
output_file=f"{MATERIAL_CACHE_DIR}/dark_{template}",
)
def render_template(
self,
colors: dict,
input_file: str,
output_file: str,
dark_mode: bool | None = None,
) -> None:
if dark_mode is None:
colors["dark_mode"] = str(self.dark_mode).lower()
else:
colors["dark_mode"] = str(dark_mode).lower()
with open(input_file) as file:
template_rendered = Template(file.read()).render(colors)
with open(output_file, "w") as file:
file.write(template_rendered)
def __reload_gtk_theme(self) -> None:
THEME_CMD = "gsettings set org.gnome.desktop.interface gtk-theme {}"
COLOR_SCHEME_CMD = "gsettings set org.gnome.desktop.interface color-scheme {}"
Utils.exec_sh_async(THEME_CMD.format("Adwaita"))
Utils.exec_sh_async(THEME_CMD.format("Material"))
Utils.exec_sh_async(COLOR_SCHEME_CMD.format("default"))
Utils.exec_sh_async(COLOR_SCHEME_CMD.format("prefer-dark"))
Utils.exec_sh_async(COLOR_SCHEME_CMD.format("default"))
def __setup(self, image_path: str) -> None:
Utils.exec_sh_async("pkill -SIGUSR1 kitty")
self._wallpaper.set_wallpaper(image_path)
app.reload_css()
self.__reload_gtk_theme()
@@ -0,0 +1,7 @@
$primary = rgb({{ primary | replace("#", "") }})
$surface = rgb({{ surface | replace("#", "") }})
$onSurface = rgb({{ onSurface | replace("#", "") }})
$primaryHex = #{{ primary }}
$surfaceHex = #{{ surface }}
$onSurfaceHex = #{{ onSurface }}
@@ -0,0 +1,27 @@
foreground {{ onSurface }}
background {{ surface }}
cursor {{ onSurface }}
color0 {{ surface }}
color8 {{ surface }}
color1 {{ error }}
color9 {{ error }}
color2 {{ inversePrimary }}
color10 {{ inversePrimary }}
color3 {{ error }}
color11 {{ error }}
color4 {{ primaryContainer }}
color12 {{ primaryContainer }}
color5 {{ onSecondaryContainer }}
color13 {{ onSecondaryContainer }}
color6 {{ primary }}
color14 {{ primary }}
color7 {{ onSurface }}
color15 {{ onSurface }}
@@ -0,0 +1,55 @@
$primary_paletteKeyColor: {{ primary_paletteKeyColor }};
$secondary_paletteKeyColor: {{ secondary_paletteKeyColor }};
$tertiary_paletteKeyColor: {{ tertiary_paletteKeyColor }};
$neutral_paletteKeyColor: {{ neutral_paletteKeyColor }};
$neutral_variant_paletteKeyColor: {{ neutral_variant_paletteKeyColor }};
$background: {{ background }};
$onBackground: {{ onBackground }};
$surface: {{ surface }};
$surfaceDim: {{ surfaceDim }};
$surfaceBright: {{ surfaceBright }};
$surfaceContainerLowest: {{ surfaceContainerLowest }};
$surfaceContainerLow: {{ surfaceContainerLow }};
$surfaceContainer: {{ surfaceContainer }};
$surfaceContainerHigh: {{ surfaceContainerHigh }};
$surfaceContainerHighest: {{ surfaceContainerHighest }};
$onSurface: {{ onSurface }};
$surfaceVariant: {{ surfaceVariant }};
$onSurfaceVariant: {{ onSurfaceVariant }};
$inverseSurface: {{ inverseSurface }};
$inverseOnSurface: {{ inverseOnSurface }};
$outline: {{ outline }};
$outlineVariant: {{ outlineVariant }};
$shadow: {{ shadow }};
$scrim: {{ scrim }};
$surfaceTint: {{ surfaceTint }};
$primary: {{ primary }};
$onPrimary: {{ onPrimary }};
$primaryContainer: {{ primaryContainer }};
$onPrimaryContainer: {{ onPrimaryContainer }};
$inversePrimary: {{ inversePrimary }};
$secondary: {{ secondary }};
$onSecondary: {{ onSecondary }};
$secondaryContainer: {{ secondaryContainer }};
$onSecondaryContainer: {{ onSecondaryContainer }};
$tertiary: {{ tertiary }};
$onTertiary: {{ onTertiary }};
$tertiaryContainer: {{ tertiaryContainer }};
$onTertiaryContainer: {{ onTertiaryContainer }};
$error: {{ error }};
$onError: {{ onError }};
$errorContainer: {{ errorContainer }};
$onErrorContainer: {{ onErrorContainer }};
$primaryFixed: {{ primaryFixed }};
$primaryFixedDim: {{ primaryFixedDim }};
$onPrimaryFixed: {{ onPrimaryFixed }};
$onPrimaryFixedVariant: {{ onPrimaryFixedVariant }};
$secondaryFixed: {{ secondaryFixed }};
$secondaryFixedDim: {{ secondaryFixedDim }};
$onSecondaryFixed: {{ onSecondaryFixed }};
$onSecondaryFixedVariant: {{ onSecondaryFixedVariant }};
$tertiaryFixed: {{ tertiaryFixed }};
$tertiaryFixedDim: {{ tertiaryFixedDim }};
$onTertiaryFixed: {{ onTertiaryFixed }};
$onTertiaryFixedVariant: {{ onTertiaryFixedVariant }};
$darkmode: {{ dark_mode }};
@@ -0,0 +1,50 @@
@define-color accent_color {{ primary }};
@define-color accent_bg_color {{ primary }};
@define-color accent_fg_color {{ surface }};
@define-color destructive_color {{ errorContainer }};
@define-color destructive_bg_color {{ errorContainer }};
@define-color destructive_fg_color {{ onSurface }};
@define-color success_color {{ tertiary }};
@define-color success_bg_color {{ tertiary }};
@define-color success_fg_color {{ onSurface }};
@define-color warning_color {{ secondary }};
@define-color warning_bg_color {{ secondary }};
@define-color warning_fg_color {{ onSurface }};
@define-color error_color {{ errorContainer }};
@define-color error_bg_color {{ errorContainer }};
@define-color error_fg_color {{ onSurface }};
@define-color window_bg_color {{ surface }};
@define-color window_fg_color {{ onSurface }};
@define-color view_bg_color {{ surface }};
@define-color view_fg_color {{ onSurface }};
@define-color headerbar_bg_color {{ surface }};
@define-color headerbar_fg_color {{ onSurface }};
@define-color headerbar_border_color {{ outline }};
@define-color headerbar_backdrop_color {{ surface }};
@define-color headerbar_shade_color {{ outline }};
@define-color sidebar_bg_color {{ surfaceContainer }};
@define-color sidebar_fg_color {{ onSurface }};
@define-color sidebar_backdrop_color {{ surfaceContainer }};
@define-color card_bg_color {{ surfaceContainer }};
@define-color card_fg_color {{ onSurface }};
@define-color card_shade_color rgba(0, 0, 0, 0.07);
@define-color thumbnail_bg_color {{ surface }};
@define-color thumbnail_fg_color {{ onSurface }};
@define-color dialog_bg_color {{ surface }};
@define-color dialog_fg_color {{ onSurface }};
@define-color popover_bg_color {{ surfaceContainer }};
@define-color popover_fg_color {{ onSurface }};
@define-color shade_color rgba(0, 0, 0, 0.36);
@define-color scrollbar_outline_color {{ outline }};
.navigation-sidebar {
background-color: {{ surfaceContainer }};
}
switch:checked {
background-color: {{ primary }};
}
switch:checked slider {
background-color: {{ onPrimary }};
}
@@ -0,0 +1,51 @@
# ---------------------SETTINGS---------------------------#
daemonize
show-failed-attempts
clock
screenshot
ignore-empty-password
indicator
font=JetBrainsMono
indicator-radius=200
indicator-thickness=20
#----------------------EFFECTS----------------------------#
effect-blur=9x5
effect-vignette=0.5:0.5
#--------------------INPUT IGNORE-------------------------#
grace-no-mouse
grace-no-touch
#--------------------DATE & TIME--------------------------#
datestr=%a,%e %B
timestr=%H:%M
fade-in=0.2
#----------------------COLORS-----------------------------#
bs-hl-color={{ error }}
inside-color=#FFFFFF00
ring-color=#FFFFFF00
line-color=#FFFFFF00
separator-color=#FFFFFF00
key-hl-color={{ primaryFixedDim }}
text-color={{ primaryFixedDim }}
text-caps-lock-color={{ tertiary }}
ring-clear-color=#FFFFFF00
text-clear-color={{ onTertiary }}
inside-clear-color={{ tertiary }}
line-clear-color=#FFFFFF00
ring-ver-color=#FFFFFF00
text-ver-color={{ onSecondary }}
inside-ver-color={{ secondary }}
line-ver-color=#FFFFFF00
ring-wrong-color=#FFFFFF00
text-wrong-color={{ onError }}
inside-wrong-color={{ error }}
line-wrong-color=#FFFFFF00
@@ -0,0 +1,18 @@
import math
def rgba_to_hex(rgba: list) -> str:
return "#{:02x}{:02x}{:02x}".format(*rgba)
def calculate_optimal_size(width: int, height: int, bitmap_size: int) -> tuple:
image_area = width * height
bitmap_area = bitmap_size**2
scale = math.sqrt(bitmap_area / image_area) if image_area > bitmap_area else 1
new_width = round(width * scale)
new_height = round(height * scale)
if new_width == 0:
new_width = 1
if new_height == 0:
new_height = 1
return new_width, new_height