Shared SaraSuite settings (theme, font, title bar) with a SaraSuite settings tab

This commit is contained in:
sarah committed 2026-09-24 23:40:21 +02:00
1 parent 089dfc005f
commit a5f5c5ca79
3 files changed
+159 -19

No files matched your search

+80 -4
View File
@@ -6,6 +6,7 @@ one accent colour (Purple/Mauve) used everywhere, not a mauve+lavender mix.
"""
import shutil
import subprocess
from dataclasses import asdict, dataclass, field
from pathlib import Path
@@ -37,7 +38,11 @@ class Palette:
AppName = "SaraFem"
FontFamily = "Fixedsys Excelsior"
# Bundled in assets/fonts and always registered, so it works as FontFamily
# without being installed. Any other FontFamily is looked up among the
# system's installed fonts.
BundledFontFamily = "Fixedsys Excelsior"
ActiveFontFamily = BundledFontFamily # set by ApplyAppearance, read by BuildTheme
CacheDir = Path.home() / ".cache" / "SaraFem"
ThumbnailCacheDir = CacheDir / "Thumbnails"
@@ -48,6 +53,9 @@ SharedConfigDir = Path.home() / ".config" / "SaraSuite"
ThemesDir = SharedConfigDir / "Themes"
ConfigDir = SharedConfigDir / "SaraFem"
ConfigPath = ConfigDir / "Config.toml"
# Settings shared by every SaraSuite program. Same key names as the matching
# fields in each program's own Config.toml.
SharedConfigPath = SharedConfigDir / "Config.toml"
BookmarksPath = ConfigDir / ".sfem_bookmarks.toml"
_OldConfigDir = Path.home() / ".config" / "SaraFem"
@@ -152,10 +160,16 @@ class AppConfig:
(nothing changes visually until the user opts in via Ctrl+B/P/H/T or edits
Config.toml directly)."""
# True: Theme, FontFamily and HideWindowTitleBar come from the shared
# ~/.config/SaraSuite/Config.toml, like every other SaraSuite program.
# False: SaraFem uses its own values below instead.
UseSharedSettings: bool = True
Theme: str = "CatppuccinMocha" # matches a file in ~/.config/SaraSuite/Themes/
FontFamily: str = BundledFontFamily
HideWindowTitleBar: bool = False # the actual OS window title bar, not the toolbar below
ShowDotfiles: bool = True
ViewMode: str = "list" # "list" or "grid"
HideWindowTitleBar: bool = False # the actual OS window title bar, not the toolbar below
# Batch-rename pattern for multi-select rename, syntax modeled on
# SaraSortd's own placeholder characters (see ~/Applications/SaraSortd's
@@ -252,6 +266,68 @@ def LoadConfig() -> AppConfig:
return AppConfig(**Filtered)
@dataclass
class SharedSettings:
"""~/.config/SaraSuite/Config.toml: the settings every SaraSuite program
shares. A program whose own UseSharedSettings is off reads these same
keys from its own Config.toml instead."""
Theme: str = "CatppuccinMocha"
FontFamily: str = BundledFontFamily
HideWindowTitleBar: bool = False
def Save(self) -> None:
SharedConfigDir.mkdir(parents=True, exist_ok=True)
SharedConfigPath.write_text(toml.dumps(asdict(self)))
def _OwnSettings(Config: AppConfig) -> SharedSettings:
return SharedSettings(Config.Theme, Config.FontFamily, Config.HideWindowTitleBar)
def LoadSharedSettings(Config: AppConfig) -> SharedSettings:
"""The shared file, created from SaraFem's own values the first time so
switching to it doesn't change anything visible."""
if not SharedConfigPath.exists():
Shared = _OwnSettings(Config)
Shared.Save()
return Shared
Result = _OwnSettings(Config) # fallback for keys the file doesn't have
try:
Data = toml.loads(SharedConfigPath.read_text())
except toml.TomlDecodeError:
return Result
for Key in SharedSettings.__dataclass_fields__:
if Key in Data:
setattr(Result, Key, Data[Key])
return Result
def EffectiveSettings(Config: AppConfig) -> SharedSettings:
"""What SaraFem actually uses: the shared settings, or its own."""
return LoadSharedSettings(Config) if Config.UseSharedSettings else _OwnSettings(Config)
def ApplyAppearance(Settings: SharedSettings) -> None:
"""Theme colours and font. Must run before anything reads Palette.X or
calls BuildTheme(). The window title bar is applied by Main."""
global ActiveFontFamily
ApplyTheme(Settings.Theme)
ActiveFontFamily = Settings.FontFamily or BundledFontFamily
def InstalledFontFamilies() -> list[str]:
"""Font families fontconfig knows about, for the font picker. The
bundled font is always first, since it isn't installed system-wide."""
try:
Result = subprocess.run(["fc-list", ":", "family"], capture_output=True, text=True, timeout=5)
Families = {Line.split(",")[0].strip() for Line in Result.stdout.splitlines() if Line.strip()}
except (OSError, subprocess.SubprocessError):
Families = set()
Families.discard(BundledFontFamily)
return [BundledFontFamily] + sorted(Families, key=str.lower)
def BuildTheme() -> ft.Theme:
ColorScheme = ft.ColorScheme(
primary=Palette.Mauve,
@@ -275,7 +351,7 @@ def BuildTheme() -> ft.Theme:
on_error=Palette.Crust,
)
return ft.Theme(
font_family=FontFamily,
font_family=ActiveFontFamily,
color_scheme=ColorScheme,
use_material3=True,
scaffold_bgcolor=Palette.Base,
@@ -283,7 +359,7 @@ def BuildTheme() -> ft.Theme:
dialog_theme=ft.DialogTheme(
bgcolor=Palette.Mantle,
shape=ft.RoundedRectangleBorder(radius=8, side=ft.BorderSide(1, Palette.Mauve)),
title_text_style=ft.TextStyle(color=Palette.Mauve, size=18, font_family=FontFamily),
title_text_style=ft.TextStyle(color=Palette.Mauve, size=18, font_family=ActiveFontFamily),
),
)