mirror of
https://git.srhtnin.garden/sarah/SaraView.git
synced 2026-10-13 18:28:14 +02:00
106 lines
3.6 KiB
Python
106 lines
3.6 KiB
Python
"""SaraView's desktop client: browse and edit files in a local root directory,
|
|
or on a SaraView server (the one on SpineS) through its API. Laid out like
|
|
SaraFem: a directory tree on the left, the file list (or an open file) on
|
|
the right."""
|
|
|
|
import os
|
|
import subprocess
|
|
from typing import Optional
|
|
|
|
import flet as ft
|
|
|
|
from App import App
|
|
from Browser import Browser
|
|
from Core import (
|
|
AppName, ApplyAppearance, AssetsDir, BuildTheme, BundledFontFamily, EffectiveSettings, LoadConfig, Palette,
|
|
ResizeHandle,
|
|
)
|
|
from Filetree import Filetree
|
|
from Settings import ShowSettingsDialog
|
|
|
|
|
|
def _SetCursorThemeFallback() -> None:
|
|
"""GTK reads XCURSOR_THEME directly and doesn't always inherit it (shows as
|
|
'Unable to load ... from the cursor theme'). Same fix as SaraFem's."""
|
|
if os.environ.get("XCURSOR_THEME"):
|
|
return
|
|
try:
|
|
Result = subprocess.run(["gsettings", "get", "org.gnome.desktop.interface", "cursor-theme"],
|
|
capture_output=True, text=True, timeout=2)
|
|
Theme = Result.stdout.strip().strip("'")
|
|
except (OSError, subprocess.SubprocessError):
|
|
Theme = ""
|
|
os.environ["XCURSOR_THEME"] = Theme or "Adwaita"
|
|
|
|
|
|
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 = 760
|
|
Page.window.min_width = 720
|
|
Page.window.min_height = 480
|
|
|
|
TheApp = App(Page, Config)
|
|
|
|
def OnPathChanged(Root: Optional[str], RelativePath: str, Reload: bool) -> None:
|
|
if Reload: # directories may have moved, so the tree starts over
|
|
Tree.Reload()
|
|
Tree.RevealPath(Root, RelativePath)
|
|
|
|
def ShowSettings(Category: str = "General") -> None:
|
|
ShowSettingsDialog(TheApp, OnSettingsSaved, Category)
|
|
|
|
def OnSettingsSaved(Reconnect: bool) -> None:
|
|
Tree.visible = Divider.visible = Config.ShowSidebar
|
|
if Reconnect:
|
|
TheApp.Connect() # its listeners reload the tree and the browser
|
|
else:
|
|
Body.update()
|
|
TheBrowser.Refresh()
|
|
|
|
def ToggleSidebar() -> None:
|
|
Config.ShowSidebar = not Config.ShowSidebar
|
|
Config.Save()
|
|
Tree.visible = Divider.visible = Config.ShowSidebar
|
|
Body.update()
|
|
|
|
def OnDrag(Delta: float) -> None:
|
|
Tree.width = max(140, (Tree.width or Config.SidebarWidth) + Delta)
|
|
Tree.update()
|
|
|
|
def OnDragEnd() -> None:
|
|
Config.SidebarWidth = int(Tree.width)
|
|
Config.Save()
|
|
|
|
TheBrowser = Browser(TheApp, OnPathChanged, lambda: ShowSettings("Connection" if TheApp.ConnectError else "General"),
|
|
ToggleSidebar)
|
|
Tree = Filetree(TheApp, TheBrowser.NavigateTo)
|
|
Divider = ResizeHandle(OnDrag, OnDragEnd)
|
|
Tree.visible = Divider.visible = Config.ShowSidebar
|
|
# STRETCH so the divider gets the full height to be dragged along.
|
|
Body = ft.Row([Tree, Divider, TheBrowser], expand=True, spacing=0, vertical_alignment=ft.CrossAxisAlignment.STRETCH)
|
|
Page.add(Body)
|
|
|
|
def OnSourceChanged() -> None:
|
|
Tree.Reload()
|
|
TheBrowser.SourceChanged()
|
|
|
|
TheApp.Listeners.append(OnSourceChanged)
|
|
TheApp.Connect()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
_SetCursorThemeFallback()
|
|
ft.run(Main, assets_dir=str(AssetsDir))
|