Files
SaraSort/Main.py
T
sarahandClaude Opus 5.5 f7ed23edf9 SaraSort: Flet GUI for configuring SaraSortd
Flowchart of inputs/outputs with editable arrows, service page (status,
controls, autostart, version, logs), config editor (form + raw), templates,
tools (warnings, filename tester, failed files) and settings with
SaraFem-compatible export/import. AppImage build and a SaraSuite manifest
in Packaging/.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 22:23:36 +02:00

112 lines
4.1 KiB
Python

"""SaraSort: a GUI for configuring SaraSortd. It doesn't sort anything itself;
it reads and edits SaraSortd's configs and controls its systemd service."""
import flet as ft
from ConfigPage import ConfigPage
from Core import (
AppName, ApplyAppearance, AssetsDir, BuildTheme, BundledFontFamily, EffectiveSettings, LoadConfig, Palette,
)
from FlowPage import FlowPage
from ServicePage import ServicePage
from SettingsPage import SettingsPage
from TemplatesPage import TemplatesPage
from ToolsPage import ToolsPage
from Widgets import App
Destinations = [
("Flow", ft.Icons.SCHEMA_OUTLINED, ft.Icons.SCHEMA),
("Service", ft.Icons.MONITOR_HEART_OUTLINED, ft.Icons.MONITOR_HEART),
("Configs", ft.Icons.TUNE_OUTLINED, ft.Icons.TUNE),
("Templates", ft.Icons.DASHBOARD_CUSTOMIZE_OUTLINED, ft.Icons.DASHBOARD_CUSTOMIZE),
("Tools", ft.Icons.BUILD_OUTLINED, ft.Icons.BUILD),
("Settings", ft.Icons.SETTINGS_OUTLINED, ft.Icons.SETTINGS),
]
Names = [Name for Name, _, _ in Destinations]
def Main(Page: ft.Page) -> None:
Config = LoadConfig()
Appearance = EffectiveSettings(Config)
ApplyAppearance(Appearance) # before anything reads Palette.X
Page.title = AppName
Page.theme_mode = ft.ThemeMode.DARK
Page.theme = BuildTheme()
Page.dark_theme = BuildTheme()
Page.fonts = {BundledFontFamily: "fonts/Fixedsys_Excelsior_Regular.ttf"}
Page.window.title_bar_hidden = Appearance.HideWindowTitleBar
Page.padding = 0
Page.bgcolor = Palette.Base
Page.window.width = 1180
Page.window.height = 780
Page.window.min_width = 760
Page.window.min_height = 520
TheApp = App(Page, Config)
Body = ft.Container(expand=True)
Pages: dict[str, ft.Control] = {}
State = {"Current": ""}
def Navigate(Name: str, **Arguments) -> None:
if Name not in Pages:
return
Previous = Pages.get(State["Current"])
if isinstance(Previous, ServicePage):
Previous.StopPolling()
State["Current"] = Name
Rail.selected_index = Names.index(Name)
Body.content = Pages[Name]
Page.update()
Shown = Pages[Name]
Shown.Refresh(**Arguments)
if isinstance(Shown, ServicePage):
Shown.StartPolling()
TheApp.Navigate = Navigate
Pages.update({
"Flow": FlowPage(TheApp),
"Service": ServicePage(TheApp),
"Configs": ConfigPage(TheApp),
"Templates": TemplatesPage(TheApp),
"Tools": ToolsPage(TheApp),
"Settings": SettingsPage(TheApp, OnSaved=lambda: None),
})
Rail = ft.NavigationRail(
selected_index=0,
label_type=ft.NavigationRailLabelType.ALL,
bgcolor=Palette.Mantle,
indicator_color=Palette.Surface0,
min_width=88,
destinations=[ft.NavigationRailDestination(icon=Icon, selected_icon=Selected, label=Name)
for Name, Icon, Selected in Destinations],
on_change=lambda e: Navigate(Names[e.control.selected_index]),
)
async def CloseWindow(e) -> None:
await Page.window.close()
TitleRow = [ft.WindowDragArea(
ft.Container(ft.Text(AppName, size=18, color=Palette.Mauve), padding=ft.Padding.only(left=16, top=6, bottom=6)),
expand=True,
)]
if Appearance.HideWindowTitleBar:
TitleRow += [
ft.IconButton(ft.Icons.MINIMIZE, icon_size=16, tooltip="Minimize",
on_click=lambda e: (setattr(Page.window, "minimized", True), Page.update())),
ft.IconButton(ft.Icons.CLOSE, icon_size=16, tooltip="Close", on_click=CloseWindow),
]
Page.add(ft.Column([
ft.Container(ft.Row(TitleRow, spacing=0), bgcolor=Palette.Mantle,
border=ft.Border.only(bottom=ft.BorderSide(1, Palette.Surface1))),
ft.Row([Rail, ft.VerticalDivider(width=1, color=Palette.Surface1), Body], expand=True, spacing=0,
vertical_alignment=ft.CrossAxisAlignment.STRETCH),
], expand=True, spacing=0))
Navigate(Config.StartPage if Config.StartPage in Pages else "Flow")
if __name__ == "__main__":
ft.run(Main, assets_dir=str(AssetsDir))