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:
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user