fix: hidden files reappear on restart, scroll jumps on selection

- Centralize item visibility in _apply_visibility: hidden if
  profile-hidden OR (hide_exported AND done)
- mark_done/unmark_done no longer touch setHidden directly
- Session resume selects first visible item after filters applied
- add_files defers to _select_first_visible to skip hidden items

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-13 16:53:17 +02:00
parent 9b8d742fde
commit 31772b898c
+33 -24
View File
@@ -1396,6 +1396,7 @@ class PlaylistWidget(QListWidget):
self._paths: list[str] = [] self._paths: list[str] = []
self._path_set: set[str] = set() # O(1) duplicate check self._path_set: set[str] = set() # O(1) duplicate check
self._done_set: set[str] = set() # paths with exported clips self._done_set: set[str] = set() # paths with exported clips
self._hidden_basenames: set[str] = set() # profile-hidden basenames
self._hide_exported = False self._hide_exported = False
self.itemClicked.connect(self._on_item_clicked) self.itemClicked.connect(self._on_item_clicked)
@@ -1410,8 +1411,7 @@ class PlaylistWidget(QListWidget):
self.addItem(os.path.basename(path)) self.addItem(os.path.basename(path))
self.setUpdatesEnabled(True) self.setUpdatesEnabled(True)
if was_empty and self._paths: if was_empty and self._paths:
self._select(0) self._select_first_visible()
self.scrollToItem(self.item(0))
def mark_done(self, path: str, n_clips: int = 0) -> None: def mark_done(self, path: str, n_clips: int = 0) -> None:
"""Gray out and show clip count on the queue item for path.""" """Gray out and show clip count on the queue item for path."""
@@ -1426,8 +1426,6 @@ class PlaylistWidget(QListWidget):
tag = f"[{n_clips}]" if n_clips else "" tag = f"[{n_clips}]" if n_clips else ""
item.setText(f"{tag} {name}") item.setText(f"{tag} {name}")
item.setForeground(QColor(100, 180, 100)) item.setForeground(QColor(100, 180, 100))
if self._hide_exported:
item.setHidden(True)
def unmark_done(self, path: str) -> None: def unmark_done(self, path: str) -> None:
"""Remove the done mark and restore default color.""" """Remove the done mark and restore default color."""
@@ -1440,23 +1438,25 @@ class PlaylistWidget(QListWidget):
return return
item.setText(os.path.basename(path)) item.setText(os.path.basename(path))
item.setForeground(QColor(200, 200, 200)) item.setForeground(QColor(200, 200, 200))
if self._hide_exported:
item.setHidden(False)
def hide_paths(self, basenames: set[str]) -> None: def set_hidden_basenames(self, basenames: set[str]) -> None:
"""Hide items whose basename is in the set (profile-based hiding).""" """Set the profile-hidden basenames and refresh visibility."""
for i, path in enumerate(self._paths): self._hidden_basenames = basenames
if os.path.basename(path) in basenames: self._apply_visibility()
item = self.item(i)
if item:
item.setHidden(True)
def set_hide_exported(self, hide: bool) -> None: def set_hide_exported(self, hide: bool) -> None:
self._hide_exported = hide self._hide_exported = hide
self._apply_visibility()
def _apply_visibility(self) -> None:
"""Centralized: item is hidden if profile-hidden OR (hide_exported AND done)."""
for i, path in enumerate(self._paths): for i, path in enumerate(self._paths):
item = self.item(i) item = self.item(i)
if item: if item is None:
item.setHidden(hide and path in self._done_set) continue
hidden = (os.path.basename(path) in self._hidden_basenames
or (self._hide_exported and path in self._done_set))
item.setHidden(hidden)
def advance(self) -> None: def advance(self) -> None:
"""Move to next visible item in queue.""" """Move to next visible item in queue."""
@@ -1467,6 +1467,17 @@ class PlaylistWidget(QListWidget):
self._select(r) self._select(r)
return return
def _select_first_visible(self) -> None:
"""Select the first non-hidden item, or item 0 if none hidden."""
for r in range(self.count()):
item = self.item(r)
if item and not item.isHidden():
self._select(r)
return
# Fallback: select first item regardless.
if self.count() > 0:
self._select(0)
def current_path(self) -> str | None: def current_path(self) -> str | None:
row = self.currentRow() row = self.currentRow()
return self._paths[row] if 0 <= row < len(self._paths) else None return self._paths[row] if 0 <= row < len(self._paths) else None
@@ -1529,8 +1540,6 @@ class PlaylistWidget(QListWidget):
elif chosen == act_hide: elif chosen == act_hide:
path = self._paths[row] path = self._paths[row]
self.hide_requested.emit(path) self.hide_requested.emit(path)
# Visually hide the item immediately.
item.setHidden(True)
class _KeyFilter(QObject): class _KeyFilter(QObject):
@@ -2004,6 +2013,7 @@ class MainWindow(QMainWindow):
if valid: if valid:
self._playlist.add_files(valid) self._playlist.add_files(valid)
self._apply_playlist_filters() self._apply_playlist_filters()
self._playlist._select_first_visible()
_log(f"Resumed session: {len(valid)} file(s)") _log(f"Resumed session: {len(valid)} file(s)")
def _show_shortcuts(self) -> None: def _show_shortcuts(self) -> None:
@@ -2094,17 +2104,16 @@ class MainWindow(QMainWindow):
def _on_hide_file(self, path: str) -> None: def _on_hide_file(self, path: str) -> None:
"""Persistently hide a file in the current profile.""" """Persistently hide a file in the current profile."""
self._db.hide_file(os.path.basename(path), self._profile) basename = os.path.basename(path)
_log(f"Hidden file: {os.path.basename(path)} in profile {self._profile}") self._db.hide_file(basename, self._profile)
self._playlist._hidden_basenames.add(basename)
self._playlist._apply_visibility()
_log(f"Hidden file: {basename} in profile {self._profile}")
def _apply_playlist_filters(self) -> None: def _apply_playlist_filters(self) -> None:
"""Apply profile-hidden files, export marks, and hide-exported filter.""" """Apply profile-hidden files, export marks, and hide-exported filter."""
self._refresh_playlist_checks() self._refresh_playlist_checks()
hidden = self._db.get_hidden_files(self._profile) self._playlist.set_hidden_basenames(self._db.get_hidden_files(self._profile))
if hidden:
self._playlist.hide_paths(hidden)
if self._chk_hide_exported.isChecked():
self._playlist.set_hide_exported(True)
def _on_open_files(self) -> None: def _on_open_files(self) -> None:
paths, _ = QFileDialog.getOpenFileNames( paths, _ = QFileDialog.getOpenFileNames(