diff --git a/Browser.py b/Browser.py index af6dadc..8ce2db8 100644 --- a/Browser.py +++ b/Browser.py @@ -356,6 +356,7 @@ class Browser(ft.Row): expand=True, border=ft.InputBorder.OUTLINE, on_change=self._OnSearchChanged, + on_submit=self._OnSearchSubmit, on_focus=lambda e: self._SetShortcutsPaused(True), on_blur=lambda e: self._SetShortcutsPaused(False), ) @@ -1027,6 +1028,17 @@ class Browser(ft.Row): self.SearchText = self.SearchField.value or "" self._RefreshEntries() + def _OnSearchSubmit(self, Event: ft.ControlEvent) -> None: + """Enter in the search field. The filter itself is already live + (on_change, every keystroke) — this is purely about Enter visibly + *doing* something instead of nothing: opens the first match, the + same "type to filter, Enter to go" pattern as VS Code's Quick Open + or a browser's address bar. (Feedback: "I can type my query, but + nothing happens when I hit enter" — true before this, the field had + no on_submit handler at all.)""" + if self.SearchText and self.CurrentEntries: + self.OpenEntry(self.CurrentEntries[0]) + def _ToggleMatchCase(self, Event: ft.ControlEvent) -> None: self.MatchCase = not self.MatchCase self.MatchCaseButton.style = self._SearchToggleStyle(self.MatchCase) @@ -2132,16 +2144,22 @@ class Browser(ft.Row): ft.Text(f"Path: {Entry}", selectable=True, size=12, color=Palette.Text), ] + SizeText: Optional[ft.Text] = None if Entry.is_dir(): try: ItemCount = sum(1 for _ in Entry.iterdir()) Rows.append(ft.Text(f"Contains: {ItemCount} item(s)", size=12, color=Palette.Text)) except OSError: Rows.append(ft.Text("Contains: can't read (permission denied)", size=12, color=Palette.Overlay0)) - # The one place a full recursive walk still happens — a single, - # deliberate "show me" click on one directory, not every row of - # every list render (see _EntrySize). - Rows.append(ft.Text(f"Size: {HumanSize(_DirectorySize(Entry))}", size=12, color=Palette.Text)) + # Feedback: "if a directory is big, entering properties takes + # forever... maybe do the calculation while showing the + # properties window?" — the dialog now opens immediately with a + # placeholder; the one remaining full recursive walk (still only + # a single, deliberate "show me" click, never per list row — see + # _EntrySize) runs off the UI thread afterward and fills this in + # once it's done, same pattern as thumbnails/folder fullness. + SizeText = ft.Text("Size: Calculating…", size=12, color=Palette.Text) + Rows.append(SizeText) else: Rows.append(ft.Text(f"Size: {HumanSize(Stat.st_size)}", size=12, color=Palette.Text)) @@ -2187,6 +2205,16 @@ class Browser(ft.Row): actions=Actions, ) self._ShowDialog(Dialog) + if SizeText is not None: + self.page.run_task(self._FillDirectorySizeAsync, Entry, SizeText) + + async def _FillDirectorySizeAsync(self, Entry: Path, SizeText: ft.Text) -> None: + Size = await asyncio.to_thread(_DirectorySize, Entry) + SizeText.value = f"Size: {HumanSize(Size)}" + try: + SizeText.update() + except Exception: + pass # the dialog was closed before the walk finished — nothing to update def _ShowAggregatePropertiesDialog(self, Entries: list[Path]) -> None: TotalSize = 0