From b0375c863ea7f61171cb1007be074760eeb25a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Hamal=20Dvo=C5=99=C3=A1k?= <mordae@anilinux.org> Date: Sun, 9 Mar 2025 11:49:42 +0100 Subject: [PATCH] Refactor directory navigation --- lazy_player/__init__.py | 100 +++++++++++++++++++------------------- lazy_player/file_model.py | 21 ++++---- 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/lazy_player/__init__.py b/lazy_player/__init__.py index dab78d0..5b1b04e 100644 --- a/lazy_player/__init__.py +++ b/lazy_player/__init__.py @@ -34,7 +34,7 @@ class MainWindow(Gtk.ApplicationWindow): super().__init__(*args, **kwargs) # Directory history stack - self.directory_history: list[str] = [] + self.directory_history: list[Path] = [] # For overlay text timeout self.overlay_hide_time = 0.0 @@ -151,31 +151,7 @@ class MainWindow(Gtk.ApplicationWindow): file_item = cast(FileItem, selected_item) if file_item.file_type == FileType.DIRECTORY: - target_path = os.path.abspath(file_item.full_path) - - # Check if we have history and if target is where we came from - if self.directory_history and os.path.samefile( - os.path.dirname(target_path), self.directory_history[-1] - ): - # Use history instead - prev_dir = self.directory_history.pop() - current_dir_name = Path(os.getcwd()).name - os.chdir(prev_dir) - self._populate_file_list() - - # Find and select the directory we came from - for i in range(self.list_store.get_n_items()): - item = self.list_store.get_item(i) - if item and cast(FileItem, item).name == current_dir_name: - self.list_view.scroll_to( - i, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None - ) - break - else: - # Regular directory navigation - self.directory_history.append(os.getcwd()) - os.chdir(file_item.full_path) - self._populate_file_list() + self._navigate_to(file_item.full_path) return position = file_item.load_attribute("position", 0) @@ -287,6 +263,46 @@ class MainWindow(Gtk.ApplicationWindow): item.connect("notify::attrs-changed", update_icon) update_icon() + def _navigate_to(self, path: Path): + # Check if we have history and if target is where we came from + if self.directory_history: + print(path, "vs", self.directory_history[-1]) + if path == self.directory_history[-1]: + print("navigate back") + self._navigate_back() + return + + print("navigate to", path) + # Regular directory navigation + self.directory_history.append(Path(os.getcwd())) + os.chdir(path) + self._populate_file_list() + + def _navigate_back(self): + if not self.directory_history: + return + + prev_dir = self.directory_history.pop() + current_dir = Path(os.getcwd()) + os.chdir(prev_dir) + self._populate_file_list() + + # Find and select the directory we came from + for i in range(self.list_store.get_n_items()): + item = self.list_store.get_item(i) + if not item: + continue + + file_item = cast(FileItem, item) + + if current_dir == file_item.full_path: + self.list_view.scroll_to( + i, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None + ) + break + + return True + def _on_selection_changed( self, selection_model: Gtk.SingleSelection, @@ -299,7 +315,7 @@ class MainWindow(Gtk.ApplicationWindow): selected_item = selection_model.get_selected_item() if selected_item: file_item = cast(FileItem, selected_item) - self.file_info_label.set_text(file_item.full_path) + self.file_info_label.set_text(file_item.name) def _toggle_play_pause(self) -> None: """Toggle between play and pause states""" @@ -396,20 +412,7 @@ class MainWindow(Gtk.ApplicationWindow): return True elif keyval == Gdk.keyval_from_name("BackSpace"): - if self.directory_history: - prev_dir = self.directory_history.pop() - current_dir_name = Path(os.getcwd()).name - os.chdir(prev_dir) - self._populate_file_list() - - # Find and select the directory we came from - for i in range(self.list_store.get_n_items()): - item = self.list_store.get_item(i) - if item and cast(FileItem, item).name == current_dir_name: - self.list_view.scroll_to( - i, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None - ) - break + self._navigate_back() return True return False @@ -537,20 +540,15 @@ class MainWindow(Gtk.ApplicationWindow): items: list[FileItem] = [] # Add parent directory - items.append(FileItem("..", FileType.DIRECTORY, "../")) + items.append(FileItem("..", FileType.DIRECTORY, Path("..").resolve())) with os.scandir(".") as it: for entry in it: - if entry.name != ".." and not entry.name.startswith("."): + if not entry.name.startswith("."): try: - if entry.is_dir(): - items.append(FileItem(entry.name, FileType.DIRECTORY, entry.name + "/")) - else: - file_item = FileItem.from_path(entry.name) - items.append(file_item) + items.append(FileItem.from_path(entry.name)) except ValueError: - # Skip unsupported file types - continue + continue # Skip unsupported file types # Sort directories first, then files, both alphabetically items.sort(key=lambda x: (x.file_type != FileType.DIRECTORY, x.name.lower())) @@ -562,7 +560,7 @@ class MainWindow(Gtk.ApplicationWindow): self.list_store.append(item) if items: - self.file_info_label.set_text(items[0].full_path) + self.file_info_label.set_text(items[0].name) class App(Gtk.Application): diff --git a/lazy_player/file_model.py b/lazy_player/file_model.py index ef640c9..833b4cd 100644 --- a/lazy_player/file_model.py +++ b/lazy_player/file_model.py @@ -2,6 +2,7 @@ from __future__ import annotations import os from enum import Enum, auto +from pathlib import Path from typing import overload import gi @@ -17,13 +18,13 @@ class FileType(Enum): class FileItem(GObject.Object): file_type: FileType - full_path: str + full_path: Path __gtype_name__ = "FileItem" attrs_changed = GObject.Property(type=int, default=0) - def __init__(self, name: str, file_type: FileType, full_path: str): + def __init__(self, name: str, file_type: FileType, full_path: Path): super().__init__() self.attrs_changed = 0 self.name = name @@ -31,18 +32,16 @@ class FileItem(GObject.Object): self.full_path = full_path @staticmethod - def from_path(path: str) -> FileItem: - name = os.path.basename(path) - if path.endswith("/"): - return FileItem(name, FileType.DIRECTORY, path) + def from_path(path: str | Path) -> FileItem: + full_path = Path(path).resolve() - parts = name.split(".") - suffix = parts[-1].lower() if len(parts) >= 2 else "" + if full_path.is_dir(): + return FileItem(full_path.name, FileType.DIRECTORY, full_path) - if suffix in ("mkv", "mp4", "avi"): - return FileItem(name, FileType.VIDEO, path) + if full_path.suffix in (".mkv", ".mp4", ".avi"): + return FileItem(full_path.name, FileType.VIDEO, full_path) - raise ValueError(f"Unsupported file type: {path}") + raise ValueError(f"Unsupported file type: {full_path}") @overload def load_attribute(self, name: str, dfl: str) -> str: ...