86 lines
2.1 KiB
Python
86 lines
2.1 KiB
Python
"""Persistent application settings (JSON).
|
||
|
||
Settings file is stored next to the executable (or next to main.py in dev).
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
from typing import Any
|
||
|
||
|
||
def _settings_path() -> Path:
|
||
"""Return the path to settings.json next to the running script / exe."""
|
||
if getattr(sys, "frozen", False):
|
||
base = Path(sys.executable).parent
|
||
else:
|
||
base = Path(__file__).resolve().parents[2] # project root
|
||
return base / "settings.json"
|
||
|
||
|
||
_DEFAULTS: dict[str, Any] = {
|
||
"theme_mode": "light", # "light" | "dark"
|
||
"theme_accent": "green", # "green" | "blue"
|
||
"health_check_enabled": False, # периодическая проверка связи с платой
|
||
"health_check_interval": 10, # интервал в секундах (5–60)
|
||
}
|
||
|
||
_cache: dict[str, Any] | None = None
|
||
|
||
|
||
def _load() -> dict[str, Any]:
|
||
global _cache
|
||
if _cache is not None:
|
||
return _cache
|
||
path = _settings_path()
|
||
if path.exists():
|
||
try:
|
||
with open(path, "r", encoding="utf-8") as f:
|
||
data = json.load(f)
|
||
if isinstance(data, dict):
|
||
_cache = {**_DEFAULTS, **data}
|
||
return _cache
|
||
except Exception:
|
||
pass
|
||
_cache = dict(_DEFAULTS)
|
||
return _cache
|
||
|
||
|
||
def _save() -> None:
|
||
path = _settings_path()
|
||
try:
|
||
with open(path, "w", encoding="utf-8") as f:
|
||
json.dump(_load(), f, ensure_ascii=False, indent=2)
|
||
except OSError:
|
||
pass
|
||
|
||
|
||
def get(key: str) -> Any:
|
||
"""Return setting value (uses default if missing)."""
|
||
return _load().get(key, _DEFAULTS.get(key))
|
||
|
||
|
||
def put(key: str, value: Any) -> None:
|
||
"""Set a value and persist to disk."""
|
||
_load()[key] = value
|
||
_save()
|
||
|
||
|
||
def theme_mode() -> str:
|
||
return str(get("theme_mode"))
|
||
|
||
|
||
def theme_accent() -> str:
|
||
return str(get("theme_accent"))
|
||
|
||
|
||
def health_check_enabled() -> bool:
|
||
return bool(get("health_check_enabled"))
|
||
|
||
|
||
def health_check_interval() -> int:
|
||
val = int(get("health_check_interval"))
|
||
return max(5, min(60, val))
|