From 252cc4e6f332d0b0fdc51bdf740f53331da23f62 Mon Sep 17 00:00:00 2001 From: pax Date: Sat, 4 Apr 2026 20:36:48 -0500 Subject: [PATCH] Favorites bulk context menu, slideshow state buttons - Add multi-select right-click menu in favorites (save all, unsave all, move all, unfavorite all) - Slideshow toolbar buttons show post state: Favorite/Unfavorite, Save enabled/disabled, Unsave enabled/disabled - State updates after every favorite/save/unsave action --- booru_viewer/gui/app.py | 21 +++++++++++++ booru_viewer/gui/favorites.py | 55 +++++++++++++++++++++++++++++++++++ booru_viewer/gui/preview.py | 6 ++++ 3 files changed, 82 insertions(+) diff --git a/booru_viewer/gui/app.py b/booru_viewer/gui/app.py index 773420d..a4e94ac 100644 --- a/booru_viewer/gui/app.py +++ b/booru_viewer/gui/app.py @@ -740,6 +740,23 @@ class BooruApp(QMainWindow): if self._fullscreen_window and self._fullscreen_window.isVisible(): self._preview._video_player.stop() self._fullscreen_window.set_media(path, info) + self._update_fullscreen_state() + + def _update_fullscreen_state(self) -> None: + """Update slideshow button states for the current post.""" + if not self._fullscreen_window: + return + idx = self._grid.selected_index + site_id = self._site_combo.currentData() + if 0 <= idx < len(self._posts) and site_id: + post = self._posts[idx] + favorited = self._db.is_favorited(site_id, post.id) + saved = False + if 0 <= idx < len(self._grid._thumbs): + saved = self._grid._thumbs[idx]._saved_locally + self._fullscreen_window.update_state(favorited, saved) + else: + self._fullscreen_window.update_state(False, False) def _on_image_done(self, path: str, info: str) -> None: self._dl_progress.hide() @@ -841,6 +858,7 @@ class BooruApp(QMainWindow): idx = self._grid.selected_index if 0 <= idx < len(self._posts): self._toggle_favorite(idx) + self._update_fullscreen_state() def _save_from_preview(self, folder: str) -> None: idx = self._grid.selected_index @@ -849,6 +867,7 @@ class BooruApp(QMainWindow): if folder and folder not in self._db.get_folders(): self._db.add_folder(folder) self._save_to_library(self._posts[idx], target) + self._update_fullscreen_state() def _unsave_from_preview(self) -> None: idx = self._grid.selected_index @@ -869,6 +888,7 @@ class BooruApp(QMainWindow): self._grid._thumbs[idx].set_saved_locally(False) else: self._status.showMessage(f"#{post.id} not in library") + self._update_fullscreen_state() def _open_fullscreen_preview(self) -> None: path = self._preview._current_path @@ -885,6 +905,7 @@ class BooruApp(QMainWindow): self._fullscreen_window.unsave_requested.connect(self._unsave_from_preview) self._fullscreen_window.destroyed.connect(self._on_fullscreen_closed) self._fullscreen_window.set_media(path, self._preview._info_label.text()) + self._update_fullscreen_state() def _on_fullscreen_closed(self) -> None: self._fullscreen_window = None diff --git a/booru_viewer/gui/favorites.py b/booru_viewer/gui/favorites.py index 8e41108..0e2a7ae 100644 --- a/booru_viewer/gui/favorites.py +++ b/booru_viewer/gui/favorites.py @@ -86,6 +86,7 @@ class FavoritesView(QWidget): self._grid.post_selected.connect(self._on_selected) self._grid.post_activated.connect(self._on_activated) self._grid.context_requested.connect(self._on_context_menu) + self._grid.multi_context_requested.connect(self._on_multi_context_menu) layout.addWidget(self._grid) def _refresh_folders(self) -> None: @@ -299,3 +300,57 @@ class FavoritesView(QWidget): delete_from_library(fav.post_id, fav.folder) self._db.remove_favorite(fav.site_id, fav.post_id) self.refresh() + + def _on_multi_context_menu(self, indices: list, pos) -> None: + favs = [self._favorites[i] for i in indices if 0 <= i < len(self._favorites)] + if not favs: + return + + menu = QMenu(self) + save_all = menu.addAction(f"Save All ({len(favs)}) to Library") + unsave_all = menu.addAction(f"Unsave All ({len(favs)}) from Library") + menu.addSeparator() + + move_menu = menu.addMenu(f"Move All ({len(favs)}) to Folder") + move_none = move_menu.addAction("Unfiled") + move_menu.addSeparator() + folder_actions = {} + for folder in self._db.get_folders(): + a = move_menu.addAction(folder) + folder_actions[id(a)] = folder + + menu.addSeparator() + unfav_all = menu.addAction(f"Unfavorite All ({len(favs)})") + + action = menu.exec(pos) + if not action: + return + + if action == save_all: + for fav in favs: + if fav.folder: + self._copy_to_library(fav, fav.folder) + else: + self._copy_to_library_unsorted(fav) + self.refresh() + elif action == unsave_all: + from ..core.cache import delete_from_library + for fav in favs: + delete_from_library(fav.post_id, fav.folder) + self.refresh() + elif action == move_none: + for fav in favs: + self._db.move_favorite_to_folder(fav.id, None) + self.refresh() + elif id(action) in folder_actions: + folder_name = folder_actions[id(action)] + for fav in favs: + self._db.move_favorite_to_folder(fav.id, folder_name) + self._copy_to_library(fav, folder_name) + self.refresh() + elif action == unfav_all: + from ..core.cache import delete_from_library + for fav in favs: + delete_from_library(fav.post_id, fav.folder) + self._db.remove_favorite(fav.site_id, fav.post_id) + self.refresh() diff --git a/booru_viewer/gui/preview.py b/booru_viewer/gui/preview.py index 7287acf..a5a3bef 100644 --- a/booru_viewer/gui/preview.py +++ b/booru_viewer/gui/preview.py @@ -83,6 +83,12 @@ class FullscreenPreview(QMainWindow): QApplication.instance().installEventFilter(self) self.showFullScreen() + def update_state(self, favorited: bool, saved: bool) -> None: + self._fav_btn.setText("Unfavorite" if favorited else "Favorite") + self._fav_btn.setFixedWidth(90 if favorited else 80) + self._save_btn.setEnabled(not saved) + self._unsave_btn.setEnabled(saved) + def set_media(self, path: str, info: str = "") -> None: self._info_label.setText(info) ext = Path(path).suffix.lower()