Save and resume cursor position when navigating

This commit is contained in:
Jan Hamal Dvořák 2025-03-10 21:05:59 +01:00
parent eb8e7d6f9d
commit 6d9b6dabd2
Signed by: mordae
GPG key ID: 1782BCC23EE007B9
2 changed files with 41 additions and 45 deletions

View file

@ -30,12 +30,16 @@ class MainWindow(Gtk.ApplicationWindow):
overlay_hide_time: float overlay_hide_time: float
last_position_save: float last_position_save: float
directory_history: list[Path]
selection_history: dict[str, int]
def __init__(self, *args: Any, thumbnailer: Thumbnailer, **kwargs: Any): def __init__(self, *args: Any, thumbnailer: Thumbnailer, **kwargs: Any):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.thumbnailer = thumbnailer self.thumbnailer = thumbnailer
# Directory history stack # Directory history stack
self.directory_history: list[Path] = [] self.directory_history = []
self.selection_history = {}
# For overlay text timeout # For overlay text timeout
self.overlay_hide_time = 0.0 self.overlay_hide_time = 0.0
@ -199,10 +203,9 @@ class MainWindow(Gtk.ApplicationWindow):
return frame_clock.get_frame_time() / 1_000_000 return frame_clock.get_frame_time() / 1_000_000
@property @property
def selection(self) -> FileItem: def selection(self) -> FileItem | None:
selected_item = self.selection_model.get_selected_item() selected_item = self.selection_model.get_selected_item()
assert selected_item return cast(FileItem, selected_item) if selected_item else None
return cast(FileItem, selected_item)
def _setup_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem): def _setup_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem):
# Create horizontal box to hold icon and label # Create horizontal box to hold icon and label
@ -247,55 +250,36 @@ class MainWindow(Gtk.ApplicationWindow):
label.set_text(item.name) label.set_text(item.name)
item.connect("notify::saved-position", update_icon) item.connect("notify::saved-position", update_icon)
item.connect("notify::saved-duration", update_icon)
update_icon() update_icon()
def _refresh(self): def _refresh(self):
selected = self.selection.full_path
self._populate_file_list() self._populate_file_list()
for i in range(self.list_model.get_n_items()): pos = self.selection_history.get(str(os.getcwd()), 0)
item = self.list_model.get_item(i) self.selection_model.set_selected(pos)
if not item: self.list_view.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None)
continue
file_item = cast(FileItem, item)
if file_item.full_path == selected:
self.list_view.scroll_to(
i, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None
)
break
def _navigate_to(self, path: Path): def _navigate_to(self, path: Path):
self.directory_history.append(Path(os.getcwd())) self.directory_history.append(Path(os.getcwd()))
os.chdir(path) os.chdir(path)
self._populate_file_list() self._populate_file_list()
pos = self.selection_history.get(str(path), 0)
self.selection_model.set_selected(pos)
self.list_view.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None)
def _navigate_back(self): def _navigate_back(self):
if not self.directory_history: if not self.directory_history:
return return
prev_dir = self.directory_history.pop() prev_dir = self.directory_history.pop()
current_dir = Path(os.getcwd())
os.chdir(prev_dir) os.chdir(prev_dir)
self._populate_file_list() self._populate_file_list()
# Find and select the directory we came from pos = self.selection_history.get(str(prev_dir), 0)
for i in range(self.list_model.get_n_items()): self.selection_model.set_selected(pos)
item = self.list_model.get_item(i) self.list_view.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None)
if not item:
continue
file_item = cast(FileItem, item)
if file_item.file_type != FileType.DIRECTORY:
continue
if current_dir == file_item.full_path:
self.list_view.scroll_to(
i, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, None
)
break
def _on_selection_changed( def _on_selection_changed(
self, self,
@ -303,9 +287,15 @@ class MainWindow(Gtk.ApplicationWindow):
position: int, position: int,
n_items: int, n_items: int,
): ):
if selection_model.get_selected() != Gtk.INVALID_LIST_POSITION: position = selection_model.get_selected()
file_item = self.selection
if position == Gtk.INVALID_LIST_POSITION:
return
self.selection_history[os.getcwd()] = position
file_item = self.selection
if file_item is not None:
# Update thumbnail if available # Update thumbnail if available
if file_item.thumbnail: if file_item.thumbnail:
gbytes = GLib.Bytes.new(cast(Any, file_item.thumbnail)) gbytes = GLib.Bytes.new(cast(Any, file_item.thumbnail))
@ -369,7 +359,9 @@ class MainWindow(Gtk.ApplicationWindow):
else: else:
self.show_overlay_text("Subtitles turned off") self.show_overlay_text("Subtitles turned off")
self.selection.saved_subtitle_track = index - 1 file_item = self.selection
if file_item is not None:
file_item.saved_subtitle_track = index - 1
else: else:
self.show_overlay_text("No subtitles available") self.show_overlay_text("No subtitles available")
@ -380,7 +372,9 @@ class MainWindow(Gtk.ApplicationWindow):
if has_audio: if has_audio:
self.show_overlay_text(f"Audio #{index} ({lang})") self.show_overlay_text(f"Audio #{index} ({lang})")
self.selection.saved_audio_track = index - 1 file_item = self.selection
if file_item is not None:
file_item.saved_audio_track = index - 1
else: else:
self.show_overlay_text("No audio tracks available") self.show_overlay_text("No audio tracks available")
@ -393,7 +387,7 @@ class MainWindow(Gtk.ApplicationWindow):
file_item = self.selection file_item = self.selection
if file_item.file_type == FileType.DIRECTORY: if file_item is None or file_item.file_type == FileType.DIRECTORY:
return return
position = file_item.saved_position position = file_item.saved_position
@ -454,7 +448,7 @@ class MainWindow(Gtk.ApplicationWindow):
file_item = self.selection file_item = self.selection
if file_item.file_type == FileType.DIRECTORY: if file_item is None or file_item.file_type == FileType.DIRECTORY:
return return
position = self.video_player.get_position() position = self.video_player.get_position()
@ -489,10 +483,12 @@ class MainWindow(Gtk.ApplicationWindow):
# Update thumbnail if available # Update thumbnail if available
file_item = self.selection file_item = self.selection
if file_item.thumbnail and not self.thumbnail_image.get_paintable():
gbytes = GLib.Bytes.new(cast(Any, file_item.thumbnail)) if file_item is not None:
texture = Gdk.Texture.new_from_bytes(gbytes) if file_item.thumbnail and not self.thumbnail_image.get_paintable():
self.thumbnail_image.set_paintable(texture) gbytes = GLib.Bytes.new(cast(Any, file_item.thumbnail))
texture = Gdk.Texture.new_from_bytes(gbytes)
self.thumbnail_image.set_paintable(texture)
return True return True

View file

@ -44,7 +44,7 @@ class FileItem(GObject.Object):
@GObject.Property(type=GObject.TYPE_UINT64) @GObject.Property(type=GObject.TYPE_UINT64)
def saved_duration(self): def saved_duration(self):
return self._load_attribute("duration", 1) or 1 return self._load_attribute("duration", 60) or 60
@saved_duration.setter @saved_duration.setter
def set_saved_duration(self, value: int): def set_saved_duration(self, value: int):