mirror of
https://git.srhtnin.garden/sarah/SaraView.git
synced 2026-10-13 18:28:14 +02:00
183 lines
4.9 KiB
Python
183 lines
4.9 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
import shutil
|
|
import tomllib
|
|
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import tomli_w
|
|
|
|
from Core import ApplicationDirectory, Config
|
|
|
|
|
|
PaletteRoles = [
|
|
"Background",
|
|
"Surface",
|
|
"SurfaceAlt",
|
|
"Border",
|
|
"Text",
|
|
"TextMuted",
|
|
"Black",
|
|
"White",
|
|
"Red",
|
|
"Orange",
|
|
"Yellow",
|
|
"Green",
|
|
"Blue",
|
|
"Purple",
|
|
]
|
|
|
|
DefaultSettings: dict[str, Any] = {
|
|
"FontFamily": "Fixedsys Excelsior",
|
|
"FontSize": 14,
|
|
"ThemeName": "CatppuccinMocha",
|
|
"ShowHiddenFolders": False,
|
|
"ShowSvFiles": False,
|
|
"ShowBreadcrumbs": True,
|
|
"UseHyphenBullets": True,
|
|
"UseAsciiFolderIcons": True,
|
|
"NavigateIntoDirectories": False,
|
|
"ShowGitBlame": False,
|
|
"NewEntryButtonsAtTop": False,
|
|
"StickyToolbar": True,
|
|
"ConfirmBeforeDelete": True,
|
|
"VisibleInBlame": True,
|
|
"ShowBlameAvatars": False,
|
|
}
|
|
|
|
DefaultThemesDirectory = ApplicationDirectory / "DefaultThemes"
|
|
|
|
|
|
def SanitizeThemeName(ThemeName: str) -> str:
|
|
if not ThemeName or "/" in ThemeName or "\\" in ThemeName or ThemeName in (".", ".."):
|
|
raise ValueError(f"Invalid theme name: {ThemeName}")
|
|
|
|
return ThemeName
|
|
|
|
|
|
def SanitizeUsernameForPath(Username: str) -> str:
|
|
if not Username or not re.fullmatch(r"[A-Za-z0-9_.-]+", Username):
|
|
raise ValueError(f"Invalid username: {Username}")
|
|
|
|
return Username
|
|
|
|
|
|
def GetDataDirectory() -> Path:
|
|
StorageConfig = Config.get("Storage", {})
|
|
RawPath = StorageConfig.get("DataDirectory", str(ApplicationDirectory / "Data"))
|
|
return Path(RawPath).expanduser().resolve()
|
|
|
|
|
|
def GetSettingsDirectory() -> Path:
|
|
return GetDataDirectory() / "Settings"
|
|
|
|
|
|
def GetSettingsPath(Username: str) -> Path:
|
|
Username = SanitizeUsernameForPath(Username)
|
|
return GetSettingsDirectory() / f"{Username}.toml"
|
|
|
|
|
|
def GetThemesDirectory() -> Path:
|
|
return GetDataDirectory() / "Themes"
|
|
|
|
|
|
def EnsureDataDirectory() -> None:
|
|
DataDirectory = GetDataDirectory()
|
|
ThemesDirectory = GetThemesDirectory()
|
|
DataDirectory.mkdir(parents=True, exist_ok=True)
|
|
GetSettingsDirectory().mkdir(parents=True, exist_ok=True)
|
|
ThemesDirectory.mkdir(parents=True, exist_ok=True)
|
|
|
|
if DefaultThemesDirectory.is_dir():
|
|
for ThemeFile in DefaultThemesDirectory.glob("*.toml"):
|
|
TargetPath = ThemesDirectory / ThemeFile.name
|
|
if not TargetPath.is_file():
|
|
shutil.copy(ThemeFile, TargetPath)
|
|
|
|
|
|
def LoadSettings(Username: str) -> dict[str, Any]:
|
|
EnsureDataDirectory()
|
|
SettingsPath = GetSettingsPath(Username)
|
|
|
|
if not SettingsPath.is_file():
|
|
with SettingsPath.open("wb") as SettingsFile:
|
|
tomli_w.dump(DefaultSettings, SettingsFile)
|
|
return dict(DefaultSettings)
|
|
|
|
with SettingsPath.open("rb") as SettingsFile:
|
|
Loaded = tomllib.load(SettingsFile)
|
|
|
|
return {**DefaultSettings, **Loaded}
|
|
|
|
|
|
def SaveSettings(Username: str, NewSettings: dict[str, Any]) -> dict[str, Any]:
|
|
EnsureDataDirectory()
|
|
SettingsPath = GetSettingsPath(Username)
|
|
Current: dict[str, Any] = {}
|
|
|
|
if SettingsPath.is_file():
|
|
with SettingsPath.open("rb") as SettingsFile:
|
|
Current = tomllib.load(SettingsFile)
|
|
|
|
Merged = {**DefaultSettings, **Current, **NewSettings}
|
|
|
|
with SettingsPath.open("wb") as SettingsFile:
|
|
tomli_w.dump(Merged, SettingsFile)
|
|
|
|
return Merged
|
|
|
|
|
|
def RenameUserSettings(OldUsername: str, NewUsername: str) -> None:
|
|
OldPath = GetSettingsPath(OldUsername)
|
|
|
|
if OldPath.is_file():
|
|
OldPath.rename(GetSettingsPath(NewUsername))
|
|
|
|
|
|
def ListThemeNames() -> list[str]:
|
|
EnsureDataDirectory()
|
|
return sorted(ThemeFile.stem for ThemeFile in GetThemesDirectory().glob("*.toml"))
|
|
|
|
|
|
def DeleteTheme(ThemeName: str) -> None:
|
|
EnsureDataDirectory()
|
|
ThemeName = SanitizeThemeName(ThemeName)
|
|
ThemePath = GetThemesDirectory() / f"{ThemeName}.toml"
|
|
|
|
if not ThemePath.is_file():
|
|
raise FileNotFoundError(f"Unknown theme: {ThemeName}")
|
|
|
|
ThemePath.unlink()
|
|
|
|
|
|
def LoadTheme(ThemeName: str) -> dict[str, str]:
|
|
EnsureDataDirectory()
|
|
ThemeName = SanitizeThemeName(ThemeName)
|
|
ThemePath = GetThemesDirectory() / f"{ThemeName}.toml"
|
|
|
|
if not ThemePath.is_file():
|
|
raise FileNotFoundError(f"Unknown theme: {ThemeName}")
|
|
|
|
with ThemePath.open("rb") as ThemeFile:
|
|
Loaded = tomllib.load(ThemeFile)
|
|
|
|
return Loaded.get("Palette", {})
|
|
|
|
|
|
def SaveTheme(ThemeName: str, Palette: dict[str, str]) -> None:
|
|
EnsureDataDirectory()
|
|
ThemeName = SanitizeThemeName(ThemeName)
|
|
|
|
MissingRoles = [Role for Role in PaletteRoles if Role not in Palette]
|
|
if MissingRoles:
|
|
FallbackPalette = LoadTheme("CatppuccinMocha")
|
|
for Role in MissingRoles:
|
|
Palette[Role] = FallbackPalette.get(Role, "#ff00ff")
|
|
|
|
ThemePath = GetThemesDirectory() / f"{ThemeName}.toml"
|
|
|
|
with ThemePath.open("wb") as ThemeFile:
|
|
tomli_w.dump({"Palette": Palette}, ThemeFile)
|