mirror of
https://git.srhtnin.garden/sarah/SaraSort.git
synced 2026-10-13 18:28:18 +02:00
152 lines
5.4 KiB
Python
152 lines
5.4 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 os
|
|
import shutil
|
|
|
|
import flet as ft
|
|
|
|
from ConfigPage import ConfigPage
|
|
from Core import (
|
|
AppName, ApplyAppearance, AssetsDir, BuildTheme, BundledFontFamily, ChipButtonStyle, DataHome, EffectiveSettings,
|
|
IsWindows, LoadConfig, Palette,
|
|
)
|
|
from FlowPage import FlowPage
|
|
from ServicePage import ServicePage
|
|
from Settings import ShowSettingsDialog
|
|
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),
|
|
|
|
]
|
|
Names = [Name for Name, _, _ in Destinations]
|
|
|
|
# When running as an AppImage, SaraSort can put itself in the app menu (like SaraSuite).
|
|
_AppImage = os.environ.get("APPIMAGE", "")
|
|
_MenuEntry = DataHome / "applications" / "SaraSort.desktop"
|
|
_MenuIcon = DataHome / "SaraSort" / "SaraSort.png"
|
|
|
|
|
|
def _SetMenuEntry(Enabled: bool) -> None:
|
|
if not Enabled:
|
|
_MenuEntry.unlink(missing_ok=True)
|
|
_MenuIcon.unlink(missing_ok=True)
|
|
return
|
|
_MenuIcon.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copy(AssetsDir / "Icon.png", _MenuIcon)
|
|
_MenuEntry.parent.mkdir(parents=True, exist_ok=True)
|
|
_MenuEntry.write_text(
|
|
"[Desktop Entry]\nType=Application\nName=SaraSort\n"
|
|
"Comment=Configure SaraSortd, the file sorting daemon\n"
|
|
f"Exec={_AppImage}\nIcon={_MenuIcon}\nTerminal=false\n"
|
|
"Categories=Utility;\nStartupNotify=true\n"
|
|
)
|
|
|
|
|
|
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
|
|
if IsWindows:
|
|
Page.window.icon = str(AssetsDir / "Icon.ico") # taskbar/title bar (Linux: the desktop entry)
|
|
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),
|
|
})
|
|
|
|
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]),
|
|
)
|
|
|
|
def ToggleMenuEntry(e) -> None:
|
|
_SetMenuEntry(not _MenuEntry.exists())
|
|
MenuButton.content = "Remove from app menu" if _MenuEntry.exists() else "Add to app menu"
|
|
MenuButton.update()
|
|
|
|
MenuButton = ft.OutlinedButton(
|
|
content="Remove from app menu" if _MenuEntry.exists() else "Add to app menu",
|
|
style=ChipButtonStyle(),
|
|
visible=bool(_AppImage),
|
|
on_click=ToggleMenuEntry,
|
|
)
|
|
SettingsButton = ft.IconButton(
|
|
icon=ft.Icons.SETTINGS_OUTLINED,
|
|
icon_color=Palette.Mauve,
|
|
tooltip="Settings",
|
|
# SaraSortd's paths may have changed, so reload the page afterwards.
|
|
on_click=lambda e: ShowSettingsDialog(TheApp, lambda: Navigate(State["Current"])),
|
|
)
|
|
|
|
Page.add(ft.Column([
|
|
ft.Container(
|
|
content=ft.Row([
|
|
ft.Text(AppName, size=24, color=Palette.Mauve),
|
|
ft.Container(expand=True),
|
|
MenuButton,
|
|
SettingsButton,
|
|
]),
|
|
padding=ft.Padding.symmetric(horizontal=16, vertical=8),
|
|
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))
|