diff --git a/ftl/core/browsing.ftl b/ftl/core/browsing.ftl index 47bbcf293..d473c8180 100644 --- a/ftl/core/browsing.ftl +++ b/ftl/core/browsing.ftl @@ -14,6 +14,11 @@ browsing-card = Card browsing-card-list = Card List browsing-card-state = Card State browsing-cards-cant-be-manually-moved-into = Cards can't be manually moved into a filtered deck. +browsing-cards-deleted = + { $count -> + [one] { $count } card deleted. + *[other] { $count } cards deleted. + } browsing-change-deck = Change Deck browsing-change-deck2 = Change Deck... browsing-change-note-type = Change Note Type diff --git a/ftl/core/decks.ftl b/ftl/core/decks.ftl index 3c74c863d..3ffe2a470 100644 --- a/ftl/core/decks.ftl +++ b/ftl/core/decks.ftl @@ -2,7 +2,6 @@ decks-add-new-deck-ctrlandn = Add New Deck (Ctrl+N) decks-are-you-sure-you-wish-to = Are you sure you wish to delete { $val }? decks-build = Build decks-cards-selected-by = cards selected by -decks-confirm-deletion = Are you sure you want to delete all selected decks including { $count } cards? decks-create-deck = Create Deck decks-custom-steps-in-minutes = Custom steps (in minutes) decks-deck = Deck diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index 9347f128d..7284af4fe 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -137,8 +137,8 @@ class DeckManager: assert cardsToo and childrenToo self.remove([did]) - def remove(self, dids: List[int]) -> None: - self.col._backend.remove_decks(dids) + def remove(self, dids: List[int]) -> int: + return self.col._backend.remove_decks(dids) def all_names_and_ids( self, skip_empty_default: bool = False, include_filtered: bool = True diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index f135b475b..5e72fe4de 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -1199,22 +1199,20 @@ class SidebarTreeView(QTreeView): self.browser.editor.saveNow(self._delete_decks) def _delete_decks(self) -> None: + def do_delete() -> None: + return self.mw.col.decks.remove(dids) + + def on_done(fut: Future) -> None: + self.mw.requireReset(reason=ResetReason.BrowserDeleteDeck, context=self) + self.browser.search() + self.browser.model.endReset() + tooltip(tr(TR.BROWSING_CARDS_DELETED, count=fut.result()), parent=self) + self.refresh() + dids = self._selected_decks() - if self.mw.deckBrowser.ask_delete_decks(dids): - - def do_delete() -> None: - return self.mw.col.decks.remove(dids) - - def on_done(fut: Future) -> None: - self.mw.requireReset(reason=ResetReason.BrowserDeleteDeck, context=self) - self.browser.search() - self.browser.model.endReset() - self.refresh() - res = fut.result() # Required to check for errors - - self.mw.checkpoint(tr(TR.DECKS_DELETE_DECK)) - self.browser.model.beginReset() - self.mw.taskman.run_in_background(do_delete, on_done) + self.mw.checkpoint(tr(TR.DECKS_DELETE_DECK)) + self.browser.model.beginReset() + self.mw.taskman.run_in_background(do_delete, on_done) def rename_node(self, item: SidebarItem, text: str) -> bool: new_name = text.replace('"', "") diff --git a/rslib/backend.proto b/rslib/backend.proto index db6ab7d8c..45ae4b6ed 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -151,7 +151,7 @@ service BackendService { rpc GetDeckLegacy(DeckID) returns (Json); rpc GetDeckNames(GetDeckNamesIn) returns (DeckNames); rpc NewDeckLegacy(Bool) returns (Json); - rpc RemoveDecks(DeckIDs) returns (Empty); + rpc RemoveDecks(DeckIDs) returns (UInt32); rpc DragDropDecks(DragDropDecksIn) returns (Empty); // deck config diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index b42f9b179..fc9b37ca4 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -662,7 +662,7 @@ impl BackendService for Backend { .map(Into::into) } - fn remove_decks(&self, input: pb::DeckIDs) -> BackendResult { + fn remove_decks(&self, input: pb::DeckIDs) -> BackendResult { self.with_col(|col| col.remove_decks_and_child_decks(&Into::>::into(input))) .map(Into::into) } @@ -1218,9 +1218,7 @@ impl BackendService for Backend { } fn expunge_tags(&self, tags: pb::String) -> BackendResult { - self.with_col(|col| { - col.expunge_tags(tags.val.as_str()).map(Into::into) - }) + self.with_col(|col| col.expunge_tags(tags.val.as_str()).map(Into::into)) } fn set_tag_expanded(&self, input: pb::SetTagExpandedIn) -> BackendResult { diff --git a/rslib/src/decks/mod.rs b/rslib/src/decks/mod.rs index 763aaf7db..668de14a3 100644 --- a/rslib/src/decks/mod.rs +++ b/rslib/src/decks/mod.rs @@ -440,9 +440,10 @@ impl Collection { self.storage.get_deck_id(&machine_name) } - pub fn remove_decks_and_child_decks(&mut self, dids: &[DeckID]) -> Result<()> { + pub fn remove_decks_and_child_decks(&mut self, dids: &[DeckID]) -> Result { // fixme: vet cache clearing self.state.deck_cache.clear(); + let mut card_count = 0; self.transact(None, |col| { let usn = col.usn()?; @@ -451,24 +452,28 @@ impl Collection { let child_decks = col.storage.child_decks(&deck)?; // top level - col.remove_single_deck(&deck, usn)?; + card_count += col.remove_single_deck(&deck, usn)?; // remove children for deck in child_decks { - col.remove_single_deck(&deck, usn)?; + card_count += col.remove_single_deck(&deck, usn)?; } } } Ok(()) - }) + })?; + Ok(card_count) } - pub(crate) fn remove_single_deck(&mut self, deck: &Deck, usn: Usn) -> Result<()> { + pub(crate) fn remove_single_deck(&mut self, deck: &Deck, usn: Usn) -> Result { // fixme: undo - match deck.kind { + let card_count = match deck.kind { DeckKind::Normal(_) => self.delete_all_cards_in_normal_deck(deck.id)?, - DeckKind::Filtered(_) => self.return_all_cards_in_filtered_deck(deck.id)?, - } + DeckKind::Filtered(_) => { + self.return_all_cards_in_filtered_deck(deck.id)?; + 0 + } + }; self.clear_aux_config_for_deck(deck.id)?; if deck.id.0 == 1 { let mut deck = deck.to_owned(); @@ -480,12 +485,13 @@ impl Collection { self.storage.remove_deck(deck.id)?; self.storage.add_deck_grave(deck.id, usn)?; } - Ok(()) + Ok(card_count) } - fn delete_all_cards_in_normal_deck(&mut self, did: DeckID) -> Result<()> { + fn delete_all_cards_in_normal_deck(&mut self, did: DeckID) -> Result { let cids = self.storage.all_cards_in_single_deck(did)?; - self.remove_cards_and_orphaned_notes(&cids) + self.remove_cards_and_orphaned_notes(&cids)?; + Ok(cids.len()) } pub fn get_all_deck_names(&self, skip_empty_default: bool) -> Result> {