mirror of
https://git.srhtnin.garden/sarah/SaraFem.git
synced 2026-10-13 18:18:11 +02:00
97 lines
3.4 KiB
Python
97 lines
3.4 KiB
Python
"""Preview pane: shows the content of the currently selected file.
|
|
SaraTag tags live in their own panel now (Tags.py), not here."""
|
|
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import flet as ft
|
|
|
|
from Core import AppConfig, Palette
|
|
from Thumbnails import GetThumbnail, IsThumbnailable
|
|
|
|
TextExtensions = {
|
|
".txt", ".md", ".py", ".json", ".toml", ".yaml", ".yml", ".js", ".ts",
|
|
".css", ".html", ".htm", ".csv", ".log", ".sh", ".fish", ".cfg", ".ini",
|
|
".scad", ".xml", ".ipynb",
|
|
}
|
|
TextPreviewCharLimit = 4000
|
|
|
|
|
|
def HumanSize(NumBytes: int) -> str:
|
|
Size = float(NumBytes)
|
|
for Unit in ("B", "KB", "MB", "GB"):
|
|
if Size < 1024 or Unit == "GB":
|
|
return f"{Size:.0f} {Unit}" if Unit == "B" else f"{Size:.1f} {Unit}"
|
|
Size /= 1024
|
|
return f"{Size:.1f} TB"
|
|
|
|
|
|
class Preview(ft.Container):
|
|
def __init__(self, Config: AppConfig, Side: str = "right"):
|
|
self.Config = Config
|
|
self.Body = ft.Column(
|
|
expand=True,
|
|
alignment=ft.MainAxisAlignment.CENTER,
|
|
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
)
|
|
BorderSide = ft.BorderSide(1, Palette.Surface1)
|
|
Border = ft.Border(right=BorderSide) if Side == "left" else ft.Border(left=BorderSide)
|
|
|
|
self.Body.controls = self._BuildContent(None)
|
|
|
|
super().__init__(
|
|
content=self.Body,
|
|
width=Config.PreviewWidth,
|
|
padding=16,
|
|
bgcolor=Palette.Mantle,
|
|
border=Border,
|
|
)
|
|
|
|
def ShowPath(self, EntryPath: Optional[Path]) -> None:
|
|
self.Body.controls = self._BuildContent(EntryPath)
|
|
self.update()
|
|
|
|
def _BuildContent(self, EntryPath: Optional[Path]) -> list[ft.Control]:
|
|
if EntryPath is None:
|
|
return [ft.Text("Nothing selected.", color=Palette.Overlay0)]
|
|
|
|
if not EntryPath.exists():
|
|
return [ft.Text("This no longer exists.", color=Palette.Overlay0)]
|
|
|
|
if EntryPath.is_dir():
|
|
return [
|
|
ft.Icon(ft.Icons.FOLDER, size=48, color=Palette.Mauve),
|
|
ft.Text(EntryPath.name, weight=ft.FontWeight.BOLD, text_align=ft.TextAlign.CENTER),
|
|
ft.Text("Directory", color=Palette.Overlay0),
|
|
]
|
|
|
|
if IsThumbnailable(EntryPath):
|
|
ThumbnailPath = GetThumbnail(EntryPath, Size=(512, 512))
|
|
if ThumbnailPath is not None:
|
|
return [
|
|
ft.Image(src=str(ThumbnailPath), fit=ft.BoxFit.CONTAIN, expand=True),
|
|
ft.Text(EntryPath.name, text_align=ft.TextAlign.CENTER),
|
|
]
|
|
|
|
if EntryPath.suffix.lower() in TextExtensions:
|
|
try:
|
|
Content = EntryPath.read_text(errors="replace")[:TextPreviewCharLimit]
|
|
except OSError:
|
|
Content = None
|
|
if Content is not None:
|
|
return [
|
|
ft.Text(EntryPath.name, weight=ft.FontWeight.BOLD),
|
|
ft.Container(
|
|
content=ft.Text(Content, selectable=True, size=12),
|
|
expand=True,
|
|
alignment=ft.Alignment.TOP_LEFT,
|
|
),
|
|
]
|
|
|
|
Stat = EntryPath.stat()
|
|
return [
|
|
ft.Icon(ft.Icons.INSERT_DRIVE_FILE_OUTLINED, size=48, color=Palette.Overlay0),
|
|
ft.Text(EntryPath.name, weight=ft.FontWeight.BOLD, text_align=ft.TextAlign.CENTER),
|
|
ft.Text(HumanSize(Stat.st_size), color=Palette.Overlay0),
|
|
]
|