mirror of
https://git.srhtnin.garden/sarah/SaraFem.git
synced 2026-10-14 18:18:12 +02:00
Fix tags crash with preview hidden; Ctrl+B toggles the sidebar
This commit is contained in:
1 parent
4c8d272719
commit
3cb1f416fb
5 files changed
+45
-7
No files matched your search
+15
-3
@@ -53,6 +53,7 @@ class Browser(ft.Row):
|
||||
OnPathChanged: Optional[Callable[[Path], None]] = None,
|
||||
OnBookmarksChanged: Optional[Callable[[], None]] = None,
|
||||
OnSidebarSettingsChanged: Optional[Callable[[], None]] = None,
|
||||
OnToggleSidebar: Optional[Callable[[], None]] = None,
|
||||
EntryFilter: Optional[Callable[[Path], bool]] = None,
|
||||
OnActivateFile: Optional[Callable[[Path], None]] = None,
|
||||
OnSelectionChanged: Optional[Callable[[], None]] = None,
|
||||
@@ -64,6 +65,7 @@ class Browser(ft.Row):
|
||||
self.OnPathChanged = OnPathChanged
|
||||
self.OnBookmarksChanged = OnBookmarksChanged
|
||||
self.OnSidebarSettingsChanged = OnSidebarSettingsChanged
|
||||
self.OnToggleSidebar = OnToggleSidebar # Ctrl+B; the sidebar lives in Main.py, not here
|
||||
# Hooks for picker mode (Picker.py), all unused in the normal window:
|
||||
# which entries to list, what double-click/Enter on a file does
|
||||
# (instead of xdg-open), and what Escape does.
|
||||
@@ -360,7 +362,7 @@ class Browser(ft.Row):
|
||||
self._Refresh()
|
||||
if self.Config.ShowPreview:
|
||||
self.PreviewPane.ShowPath(None)
|
||||
if self.Config.ShowTags:
|
||||
if self._TagsShown():
|
||||
self.TagPanel.ShowPath(None)
|
||||
if self.OnPathChanged:
|
||||
self.OnPathChanged(TargetPath)
|
||||
@@ -468,9 +470,16 @@ class Browser(ft.Row):
|
||||
ShowPath = self.SelectedPath if len(self.SelectedPaths) <= 1 else None
|
||||
if self.Config.ShowPreview:
|
||||
self.PreviewPane.ShowPath(ShowPath)
|
||||
if self.Config.ShowTags:
|
||||
if self._TagsShown():
|
||||
self.TagPanel.ShowPath(ShowPath)
|
||||
|
||||
def _TagsShown(self) -> bool:
|
||||
"""Whether the tags panel is actually in the window. Tags placed
|
||||
"under_preview" live in the preview column, so hiding the preview
|
||||
(Ctrl+P) hides them too even with ShowTags on; updating the panel then
|
||||
crashed with "TagPanel must be added to the page first"."""
|
||||
return self.Config.ShowTags and (self.Config.TagsPosition != "under_preview" or self.Config.ShowPreview)
|
||||
|
||||
def _TargetSelection(self, Entry: Path) -> list[Path]:
|
||||
"""What a right-click/menu action on Entry should operate on: the
|
||||
whole live selection if Entry is part of a multi-selection, otherwise
|
||||
@@ -747,8 +756,11 @@ class Browser(ft.Row):
|
||||
self.GoForward()
|
||||
elif Event.key == "A" and Event.ctrl:
|
||||
self._SelectAll()
|
||||
elif Event.key == "B" and Event.ctrl:
|
||||
elif Event.key == "B" and Event.ctrl and Event.shift:
|
||||
self._ToggleBreadcrumbs()
|
||||
elif Event.key == "B" and Event.ctrl:
|
||||
if self.OnToggleSidebar:
|
||||
self.OnToggleSidebar()
|
||||
elif Event.key == "P" and Event.ctrl:
|
||||
self._TogglePreview()
|
||||
elif Event.key == "H" and Event.ctrl:
|
||||
|
||||
@@ -149,7 +149,7 @@ class SaraTagIntegrationConfig:
|
||||
@dataclass
|
||||
class AppConfig:
|
||||
"""Persisted user settings. Defaults match SaraFem's existing behaviour
|
||||
(nothing changes visually until the user opts in via Ctrl+B/P/H or edits
|
||||
(nothing changes visually until the user opts in via Ctrl+B/P/H/T or edits
|
||||
Config.toml directly)."""
|
||||
|
||||
Theme: str = "CatppuccinMocha" # matches a file in ~/.config/SaraSuite/Themes/
|
||||
|
||||
+14
-3
@@ -165,14 +165,24 @@ class DevicesPanel(ft.Container):
|
||||
self.DeviceTiles: dict[str, ft.ListTile] = {}
|
||||
self.RefreshScheduled = False
|
||||
self.Busy: set[str] = set() # devices being mounted/ejected right now
|
||||
self.Unmounted = False
|
||||
|
||||
self.List = ft.ListView(spacing=0)
|
||||
self.List.controls = self._BuildTiles()
|
||||
super().__init__(content=self.List, padding=0)
|
||||
|
||||
def did_mount(self) -> None:
|
||||
self.Unmounted = False
|
||||
self.page.run_task(self._Start)
|
||||
|
||||
def will_unmount(self) -> None:
|
||||
# The sidebar gets rebuilt when its settings change; close this panel's
|
||||
# D-Bus connection so old panels don't pile up listening to udisks2.
|
||||
self.Unmounted = True
|
||||
if self.Client is not None:
|
||||
self.Client.Bus.disconnect()
|
||||
self.Client = None
|
||||
|
||||
async def _Start(self) -> None:
|
||||
try:
|
||||
self.Client = await UDisksClient.Connect()
|
||||
@@ -184,20 +194,21 @@ class DevicesPanel(ft.Container):
|
||||
await self._Refresh(IsStartup=True)
|
||||
|
||||
async def _PollLoop(self) -> None:
|
||||
while True:
|
||||
while not self.Unmounted:
|
||||
self._Show(ListFallbackDevices())
|
||||
await asyncio.sleep(PollInterval)
|
||||
|
||||
def _ScheduleRefresh(self) -> None:
|
||||
# One plug-in fires a burst of signals; refresh once per burst.
|
||||
if not self.RefreshScheduled:
|
||||
if not self.RefreshScheduled and not self.Unmounted:
|
||||
self.RefreshScheduled = True
|
||||
self.page.run_task(self._DelayedRefresh)
|
||||
|
||||
async def _DelayedRefresh(self) -> None:
|
||||
await asyncio.sleep(0.25)
|
||||
self.RefreshScheduled = False
|
||||
await self._Refresh()
|
||||
if self.Client is not None and not self.Unmounted:
|
||||
await self._Refresh()
|
||||
|
||||
async def _Refresh(self, IsStartup: bool = False) -> None:
|
||||
try:
|
||||
|
||||
@@ -101,6 +101,19 @@ def _BuildWindow(Config, StartPath: Path, **BrowserHooks) -> tuple[ft.Row, Brows
|
||||
SidebarView = None
|
||||
return Layout
|
||||
|
||||
def OnToggleSidebar() -> None:
|
||||
# Ctrl+B. Hides the existing sidebar instead of rebuilding it, so its
|
||||
# Devices panel keeps its udisks2 connection instead of opening a new one.
|
||||
Config.ShowSidebar = not Config.ShowSidebar
|
||||
Config.Save()
|
||||
if SidebarView is None:
|
||||
OnSidebarSettingsChanged() # it didn't exist yet (started hidden)
|
||||
return
|
||||
SidebarView.visible = Config.ShowSidebar
|
||||
SidebarView.update()
|
||||
if Config.ShowSidebar:
|
||||
SidebarView.UpdateSelection(BrowserView.CurrentPath)
|
||||
|
||||
def OnSidebarSettingsChanged() -> None:
|
||||
# Sidebar's presence/side/width and its sections aren't owned by
|
||||
# Browser, so rebuilding it lives here rather than needing a restart.
|
||||
@@ -115,6 +128,7 @@ def _BuildWindow(Config, StartPath: Path, **BrowserHooks) -> tuple[ft.Row, Brows
|
||||
OnPathChanged=OnPathChanged,
|
||||
OnBookmarksChanged=OnBookmarksChanged,
|
||||
OnSidebarSettingsChanged=OnSidebarSettingsChanged,
|
||||
OnToggleSidebar=OnToggleSidebar,
|
||||
**BrowserHooks,
|
||||
)
|
||||
OuterRow.controls = BuildOuterLayout()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
flet>=1.0,<2.0
|
||||
flet-desktop>=1.0,<2.0 # the desktop client; otherwise Flet fetches it on first launch and quits once
|
||||
pillow
|
||||
send2trash
|
||||
toml
|
||||
|
||||
Reference in new issue
Block a user