Browse multi-select: split library + bookmark actions, conditional visibility
The browse grid's multi-select right-click menu collapsed library and bookmark actions into a single "Remove All Bookmarks" entry that did *both* — it called delete_from_library and remove_bookmark per post, and was unconditionally visible regardless of selection state. Two problems: 1. There was no way to bulk-unsave files from the library without also stripping the bookmarks. Saved-but-not-bookmarked posts had no bulk-unsave path at all. 2. The single misleadingly-named action didn't match the single-post right-click menu's clean separation of "Save to Library / Unsave from Library" vs. "Bookmark as / Remove Bookmark". Reshape: split into four distinct actions, each with symmetric conditional visibility: - Save All to Library → shown only if any post is unsaved - Unsave All from Library → shown only if any post is saved (NEW) - Bookmark All → shown only if any post is unbookmarked - Remove All Bookmarks → shown only if any post is bookmarked Mixed selections show whichever subset of the four is relevant. The new Unsave All from Library calls a new _bulk_unsave method that mirrors the _bulk_save shape but synchronously (delete_from_library is a filesystem op, no httpx round-trip). Remove All Bookmarks now *only* removes bookmarks — it no longer touches the library, matching the single-post Remove Bookmark action's scope. Always-shown actions (Download All, Copy All URLs) stay below a separator at the bottom. Verified: - Multi-select unbookmarked+unsaved posts → only Save All / Bookmark All - Multi-select saved-not-bookmarked → only Unsave All / Bookmark All - Multi-select bookmarked+saved → only Unsave All / Remove All Bookmarks - Mixed selection → all four appear - Unsave All from Library removes files, leaves bookmarks - Remove All Bookmarks removes bookmarks, leaves files
This commit is contained in:
parent
c4efdb76f8
commit
db774fc33e
@ -2411,28 +2411,65 @@ class BooruApp(QMainWindow):
|
||||
return False
|
||||
|
||||
def _on_multi_context_menu(self, indices: list, pos) -> None:
|
||||
"""Context menu for multi-selected posts."""
|
||||
"""Context menu for multi-selected posts.
|
||||
|
||||
Library and bookmark actions are split into independent
|
||||
save/unsave and bookmark/remove-bookmark pairs (mirroring the
|
||||
single-post menu's separation), with symmetric conditional
|
||||
visibility: each action only appears when the selection actually
|
||||
contains posts the action would affect. Save All to Library
|
||||
appears only when at least one post is unsaved; Unsave All from
|
||||
Library only when at least one is saved; Bookmark All only when
|
||||
at least one is unbookmarked; Remove All Bookmarks only when at
|
||||
least one is bookmarked.
|
||||
"""
|
||||
posts = [self._posts[i] for i in indices if 0 <= i < len(self._posts)]
|
||||
if not posts:
|
||||
return
|
||||
count = len(posts)
|
||||
|
||||
site_id = self._site_combo.currentData()
|
||||
any_bookmarked = bool(site_id) and any(self._db.is_bookmarked(site_id, p.id) for p in posts)
|
||||
any_unbookmarked = bool(site_id) and any(not self._db.is_bookmarked(site_id, p.id) for p in posts)
|
||||
any_saved = any(self._is_post_saved(p.id) for p in posts)
|
||||
any_unsaved = any(not self._is_post_saved(p.id) for p in posts)
|
||||
|
||||
menu = QMenu(self)
|
||||
fav_all = menu.addAction(f"Bookmark All ({count})")
|
||||
|
||||
save_menu = menu.addMenu(f"Save All to Library ({count})")
|
||||
save_unsorted = save_menu.addAction("Unfiled")
|
||||
save_folder_actions = {}
|
||||
from ..core.config import library_folders
|
||||
for folder in library_folders():
|
||||
a = save_menu.addAction(folder)
|
||||
save_folder_actions[id(a)] = folder
|
||||
save_menu.addSeparator()
|
||||
save_new = save_menu.addAction("+ New Folder...")
|
||||
# Library section
|
||||
save_menu = None
|
||||
save_unsorted = None
|
||||
save_new = None
|
||||
save_folder_actions: dict[int, str] = {}
|
||||
if any_unsaved:
|
||||
from ..core.config import library_folders
|
||||
save_menu = menu.addMenu(f"Save All to Library ({count})")
|
||||
save_unsorted = save_menu.addAction("Unfiled")
|
||||
for folder in library_folders():
|
||||
a = save_menu.addAction(folder)
|
||||
save_folder_actions[id(a)] = folder
|
||||
save_menu.addSeparator()
|
||||
save_new = save_menu.addAction("+ New Folder...")
|
||||
|
||||
menu.addSeparator()
|
||||
unfav_all = menu.addAction(f"Remove All Bookmarks ({count})")
|
||||
menu.addSeparator()
|
||||
unsave_lib_all = None
|
||||
if any_saved:
|
||||
unsave_lib_all = menu.addAction(f"Unsave All from Library ({count})")
|
||||
|
||||
# Bookmark section
|
||||
if (any_unsaved or any_saved) and (any_unbookmarked or any_bookmarked):
|
||||
menu.addSeparator()
|
||||
|
||||
fav_all = None
|
||||
if any_unbookmarked:
|
||||
fav_all = menu.addAction(f"Bookmark All ({count})")
|
||||
|
||||
unfav_all = None
|
||||
if any_bookmarked:
|
||||
unfav_all = menu.addAction(f"Remove All Bookmarks ({count})")
|
||||
|
||||
# Always-shown actions
|
||||
if any_unsaved or any_saved or any_unbookmarked or any_bookmarked:
|
||||
menu.addSeparator()
|
||||
batch_dl = menu.addAction(f"Download All ({count})...")
|
||||
copy_urls = menu.addAction("Copy All URLs")
|
||||
|
||||
@ -2440,11 +2477,11 @@ class BooruApp(QMainWindow):
|
||||
if not action:
|
||||
return
|
||||
|
||||
if action == fav_all:
|
||||
if fav_all is not None and action == fav_all:
|
||||
self._bulk_bookmark(indices, posts)
|
||||
elif action == save_unsorted:
|
||||
elif save_unsorted is not None and action == save_unsorted:
|
||||
self._bulk_save(indices, posts, None)
|
||||
elif action == save_new:
|
||||
elif save_new is not None and action == save_new:
|
||||
from PySide6.QtWidgets import QInputDialog, QMessageBox
|
||||
name, ok = QInputDialog.getText(self, "New Folder", "Folder name:")
|
||||
if ok and name.strip():
|
||||
@ -2457,25 +2494,24 @@ class BooruApp(QMainWindow):
|
||||
self._bulk_save(indices, posts, name.strip())
|
||||
elif id(action) in save_folder_actions:
|
||||
self._bulk_save(indices, posts, save_folder_actions[id(action)])
|
||||
elif unsave_lib_all is not None and action == unsave_lib_all:
|
||||
self._bulk_unsave(indices, posts)
|
||||
elif action == batch_dl:
|
||||
from .dialogs import select_directory
|
||||
dest = select_directory(self, "Download to folder")
|
||||
if dest:
|
||||
self._batch_download_posts(posts, dest)
|
||||
elif action == unfav_all:
|
||||
site_id = self._site_combo.currentData()
|
||||
elif unfav_all is not None and action == unfav_all:
|
||||
if site_id:
|
||||
from ..core.cache import delete_from_library
|
||||
for post in posts:
|
||||
# Single call now walks every library folder by post id.
|
||||
delete_from_library(post.id)
|
||||
self._db.remove_bookmark(site_id, post.id)
|
||||
for idx in indices:
|
||||
if 0 <= idx < len(self._grid._thumbs):
|
||||
self._grid._thumbs[idx].set_bookmarked(False)
|
||||
self._grid._thumbs[idx].set_saved_locally(False)
|
||||
self._grid._clear_multi()
|
||||
self._status.showMessage(f"Removed {count} bookmarks")
|
||||
if self._stack.currentIndex() == 1:
|
||||
self._bookmarks_view.refresh()
|
||||
elif action == copy_urls:
|
||||
urls = "\n".join(p.file_url for p in posts)
|
||||
QApplication.clipboard().setText(urls)
|
||||
@ -2537,6 +2573,29 @@ class BooruApp(QMainWindow):
|
||||
|
||||
self._run_async(_do)
|
||||
|
||||
def _bulk_unsave(self, indices: list[int], posts: list[Post]) -> None:
|
||||
"""Bulk-remove selected posts from the library.
|
||||
|
||||
Mirrors `_bulk_save` shape but synchronously — `delete_from_library`
|
||||
is a filesystem op, no httpx round-trip needed. Touches only the
|
||||
library (filesystem); bookmarks are a separate DB-backed concept
|
||||
and stay untouched. The grid's saved-locally dot clears for every
|
||||
selection slot regardless of whether the file was actually present
|
||||
— the user's intent is "make these not-saved", and a missing file
|
||||
is already not-saved.
|
||||
"""
|
||||
from ..core.cache import delete_from_library
|
||||
for post in posts:
|
||||
delete_from_library(post.id)
|
||||
for idx in indices:
|
||||
if 0 <= idx < len(self._grid._thumbs):
|
||||
self._grid._thumbs[idx].set_saved_locally(False)
|
||||
self._grid._clear_multi()
|
||||
self._status.showMessage(f"Removed {len(posts)} from library")
|
||||
if self._stack.currentIndex() == 2:
|
||||
self._library_view.refresh()
|
||||
self._update_fullscreen_state()
|
||||
|
||||
def _ensure_bookmarked(self, post: Post) -> None:
|
||||
"""Bookmark a post if not already bookmarked."""
|
||||
site_id = self._site_combo.currentData()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user