Refactor directory navigation
This commit is contained in:
parent
2fd45b556f
commit
b0375c863e
2 changed files with 59 additions and 62 deletions
lazy_player
|
@ -34,7 +34,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Directory history stack
|
# Directory history stack
|
||||||
self.directory_history: list[str] = []
|
self.directory_history: list[Path] = []
|
||||||
|
|
||||||
# For overlay text timeout
|
# For overlay text timeout
|
||||||
self.overlay_hide_time = 0.0
|
self.overlay_hide_time = 0.0
|
||||||
|
@ -151,31 +151,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
file_item = cast(FileItem, selected_item)
|
file_item = cast(FileItem, selected_item)
|
||||||
|
|
||||||
if file_item.file_type == FileType.DIRECTORY:
|
if file_item.file_type == FileType.DIRECTORY:
|
||||||
target_path = os.path.abspath(file_item.full_path)
|
self._navigate_to(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()
|
|
||||||
return
|
return
|
||||||
|
|
||||||
position = file_item.load_attribute("position", 0)
|
position = file_item.load_attribute("position", 0)
|
||||||
|
@ -287,6 +263,46 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
item.connect("notify::attrs-changed", update_icon)
|
item.connect("notify::attrs-changed", update_icon)
|
||||||
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(
|
def _on_selection_changed(
|
||||||
self,
|
self,
|
||||||
selection_model: Gtk.SingleSelection,
|
selection_model: Gtk.SingleSelection,
|
||||||
|
@ -299,7 +315,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
selected_item = selection_model.get_selected_item()
|
selected_item = selection_model.get_selected_item()
|
||||||
if selected_item:
|
if selected_item:
|
||||||
file_item = cast(FileItem, 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:
|
def _toggle_play_pause(self) -> None:
|
||||||
"""Toggle between play and pause states"""
|
"""Toggle between play and pause states"""
|
||||||
|
@ -396,20 +412,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif keyval == Gdk.keyval_from_name("BackSpace"):
|
elif keyval == Gdk.keyval_from_name("BackSpace"):
|
||||||
if self.directory_history:
|
self._navigate_back()
|
||||||
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
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -537,20 +540,15 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
items: list[FileItem] = []
|
items: list[FileItem] = []
|
||||||
|
|
||||||
# Add parent directory
|
# Add parent directory
|
||||||
items.append(FileItem("..", FileType.DIRECTORY, "../"))
|
items.append(FileItem("..", FileType.DIRECTORY, Path("..").resolve()))
|
||||||
|
|
||||||
with os.scandir(".") as it:
|
with os.scandir(".") as it:
|
||||||
for entry in it:
|
for entry in it:
|
||||||
if entry.name != ".." and not entry.name.startswith("."):
|
if not entry.name.startswith("."):
|
||||||
try:
|
try:
|
||||||
if entry.is_dir():
|
items.append(FileItem.from_path(entry.name))
|
||||||
items.append(FileItem(entry.name, FileType.DIRECTORY, entry.name + "/"))
|
|
||||||
else:
|
|
||||||
file_item = FileItem.from_path(entry.name)
|
|
||||||
items.append(file_item)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Skip unsupported file types
|
continue # Skip unsupported file types
|
||||||
continue
|
|
||||||
|
|
||||||
# Sort directories first, then files, both alphabetically
|
# Sort directories first, then files, both alphabetically
|
||||||
items.sort(key=lambda x: (x.file_type != FileType.DIRECTORY, x.name.lower()))
|
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)
|
self.list_store.append(item)
|
||||||
|
|
||||||
if items:
|
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):
|
class App(Gtk.Application):
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
from pathlib import Path
|
||||||
from typing import overload
|
from typing import overload
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
@ -17,13 +18,13 @@ class FileType(Enum):
|
||||||
|
|
||||||
class FileItem(GObject.Object):
|
class FileItem(GObject.Object):
|
||||||
file_type: FileType
|
file_type: FileType
|
||||||
full_path: str
|
full_path: Path
|
||||||
|
|
||||||
__gtype_name__ = "FileItem"
|
__gtype_name__ = "FileItem"
|
||||||
|
|
||||||
attrs_changed = GObject.Property(type=int, default=0)
|
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__()
|
super().__init__()
|
||||||
self.attrs_changed = 0
|
self.attrs_changed = 0
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -31,18 +32,16 @@ class FileItem(GObject.Object):
|
||||||
self.full_path = full_path
|
self.full_path = full_path
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_path(path: str) -> FileItem:
|
def from_path(path: str | Path) -> FileItem:
|
||||||
name = os.path.basename(path)
|
full_path = Path(path).resolve()
|
||||||
if path.endswith("/"):
|
|
||||||
return FileItem(name, FileType.DIRECTORY, path)
|
|
||||||
|
|
||||||
parts = name.split(".")
|
if full_path.is_dir():
|
||||||
suffix = parts[-1].lower() if len(parts) >= 2 else ""
|
return FileItem(full_path.name, FileType.DIRECTORY, full_path)
|
||||||
|
|
||||||
if suffix in ("mkv", "mp4", "avi"):
|
if full_path.suffix in (".mkv", ".mp4", ".avi"):
|
||||||
return FileItem(name, FileType.VIDEO, path)
|
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
|
@overload
|
||||||
def load_attribute(self, name: str, dfl: str) -> str: ...
|
def load_attribute(self, name: str, dfl: str) -> str: ...
|
||||||
|
|
Loading…
Reference in a new issue