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: ...