Files
Vual/src/vual/config.py
T
2026-03-19 05:35:55 +10:00

140 lines
6.1 KiB
Python

"""Configuration management for Vual.
Stores settings in ~/.config/vual/config.json
"""
import json
from dataclasses import dataclass, field
from pathlib import Path
_DEFAULT_PROTONHAX = str(Path.home() / ".local" / "share" / "vual" / "bin" / "protonhax")
_DEFAULT_TEMPLATE = f"{_DEFAULT_PROTONHAX} init %COMMAND%"
_DEFAULT_EXCLUDED = ["^Proton", "^Steam Linux Runtime"]
# Config file location
CONFIG_PATH = Path.home() / ".config" / "vual" / "config.json"
# Tile size presets: small=120, medium=150, large=180
TILE_SIZES = {"small": 120, "medium": 150, "large": 180}
@dataclass
class Config:
"""Application configuration.
Attributes:
ce_executable: Path to Cheat Engine executable.
steam_path: Path to Steam installation directory.
lookup_enabled: Whether to look up game info.
launch_options_template: Template for Steam launch options.
excluded_app_patterns: Regex patterns to exclude apps.
window_width: Main window width.
window_height: Main window height.
color_scheme: Color scheme ("system", "light", "dark").
tile_size: Tile size preset ("small", "medium", "large").
sort_by: Sort order ("name", "status").
ce_language: CE language ("system", "ru_RU").
wine_theme: Wine color theme ("system", "dark", "light").
app_language: Application UI language ("system", "en", "ru").
transparent_window: Enable semi-transparent window background.
guide_shown: Whether the startup guide has been shown.
"""
ce_executable: str = "~/.local/share/vual/cheatengine/cheatengine-x86_64.exe"
steam_path: str = "~/.local/share/Steam"
lookup_enabled: bool = True
launch_options_template: str = field(default_factory=lambda: _DEFAULT_TEMPLATE)
excluded_app_patterns: list[str] = field(default_factory=lambda: _DEFAULT_EXCLUDED.copy())
window_width: int = 1000
window_height: int = 700
color_scheme: str = "system"
tile_size: str = "medium"
sort_by: str = "name"
ce_language: str = "system"
wine_theme: str = "system"
app_language: str = "system"
transparent_window: bool = False
guide_shown: bool = False
# ════════════════════════════════════════════════════════════════
# Load / Save
# ════════════════════════════════════════════════════════════════
@classmethod
def load(cls) -> "Config":
"""Load configuration from JSON file.
Returns:
Config instance with loaded or default values.
"""
if CONFIG_PATH.exists():
try:
data = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
return cls(
ce_executable=data.get("ce_executable", cls.ce_executable),
steam_path=data.get("steam_path", cls.steam_path),
lookup_enabled=data.get("lookup_enabled", cls.lookup_enabled),
launch_options_template=data.get("launch_options_template", _DEFAULT_TEMPLATE),
excluded_app_patterns=data.get("excluded_app_patterns", _DEFAULT_EXCLUDED.copy()),
window_width=data.get("window_width", cls.window_width),
window_height=data.get("window_height", cls.window_height),
color_scheme=data.get("color_scheme", cls.color_scheme),
tile_size=data.get("tile_size", cls.tile_size),
sort_by=data.get("sort_by", cls.sort_by),
ce_language=data.get("ce_language", cls.ce_language),
wine_theme=data.get("wine_theme", cls.wine_theme),
app_language=data.get("app_language", cls.app_language),
transparent_window=data.get("transparent_window", cls.transparent_window),
guide_shown=data.get("guide_shown", cls.guide_shown),
)
except (json.JSONDecodeError, OSError):
pass
return cls()
def save(self) -> Path:
"""Save configuration to JSON file.
Returns:
Path to the saved config file.
"""
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
data = {
"ce_executable": self.ce_executable,
"steam_path": self.steam_path,
"lookup_enabled": self.lookup_enabled,
"launch_options_template": self.launch_options_template,
"excluded_app_patterns": self.excluded_app_patterns,
"window_width": self.window_width,
"window_height": self.window_height,
"color_scheme": self.color_scheme,
"tile_size": self.tile_size,
"sort_by": self.sort_by,
"ce_language": self.ce_language,
"wine_theme": self.wine_theme,
"app_language": self.app_language,
"transparent_window": self.transparent_window,
"guide_shown": self.guide_shown,
}
CONFIG_PATH.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
return CONFIG_PATH
# ════════════════════════════════════════════════════════════════
# Derived Paths
# ════════════════════════════════════════════════════════════════
@property
def steamapps_path(self) -> Path:
"""Path to Steam's steamapps directory."""
return Path(self.steam_path).expanduser() / "steamapps"
@property
def ce_executable_path(self) -> Path:
"""Expanded path to CE executable."""
return Path(self.ce_executable).expanduser()
@property
def ce_exists(self) -> bool:
"""Check if CE executable exists."""
return self.ce_executable_path.is_file()