Skip to content

Commit

Permalink
Empty cards is undoable
Browse files Browse the repository at this point in the history
If there was a reason for this operation not to be undoable, I can't easily guess it. My main hyposhesis was that the number of deleted card may be too big. But I realized that deleting a deck is undoable and may delete as many note.

As you may know, I realized that only the undoable operations triggered notification in AnkiDroid that we may have to update the UI. And while I just wanted to trigger more notifications, some reviewers thought it would be nicer if the operation were returning a OpChanges. So here it's done. If you would please consider merging it.

I decided to introduce a new string because the closest strings I could find currently are "Empty cards..." and the trailing commas don't seem nice in "undo". And the title, which we may not be able to reuse in all language
  • Loading branch information
Arthur-Milchior committed Aug 28, 2024
1 parent be2f013 commit 01f4426
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 9 deletions.
1 change: 1 addition & 0 deletions ftl/core/actions.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ actions-decks = Decks
actions-decrement-value = Decrement value
actions-delete = Delete
actions-export = Export
actions-empty-cards = Empty Cards
actions-filter = Filter
actions-help = Help
actions-increment-value = Increment value
Expand Down
2 changes: 1 addition & 1 deletion proto/anki/cards.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import "anki/collection.proto";
service CardsService {
rpc GetCard(CardId) returns (Card);
rpc UpdateCards(UpdateCardsRequest) returns (collection.OpChanges);
rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty);
rpc RemoveCards(RemoveCardsRequest) returns (collection.OpChangesWithCount);
rpc SetDeck(SetDeckRequest) returns (collection.OpChangesWithCount);
rpc SetFlag(SetFlagRequest) returns (collection.OpChangesWithCount);
}
Expand Down
6 changes: 4 additions & 2 deletions pylib/anki/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,9 +604,11 @@ def is_empty(self) -> bool:
def card_count(self) -> Any:
return self.db.scalar("select count() from cards")

def remove_cards_and_orphaned_notes(self, card_ids: Sequence[CardId]) -> None:
def remove_cards_and_orphaned_notes(
self, card_ids: Sequence[CardId]
) -> OpChangesWithCount:
"You probably want .remove_notes_by_card() instead."
self._backend.remove_cards(card_ids=card_ids)
return self._backend.remove_cards(card_ids=card_ids)

def set_deck(self, card_ids: Sequence[CardId], deck_id: int) -> OpChangesWithCount:
return self._backend.set_deck(card_ids=card_ids, deck_id=deck_id)
Expand Down
4 changes: 2 additions & 2 deletions rslib/src/card/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ impl Collection {

/// Remove cards and any resulting orphaned notes.
/// Expects a transaction.
pub(crate) fn remove_cards_and_orphaned_notes(&mut self, cids: &[CardId]) -> Result<()> {
pub(crate) fn remove_cards_and_orphaned_notes(&mut self, cids: &[CardId]) -> Result<usize> {
let usn = self.usn()?;
let mut nids = HashSet::new();
for cid in cids {
Expand All @@ -342,7 +342,7 @@ impl Collection {
}
}

Ok(())
Ok(cids.len())
}

pub fn set_deck(&mut self, cards: &[CardId], deck_id: DeckId) -> Result<OpOutput<usize>> {
Expand Down
12 changes: 8 additions & 4 deletions rslib/src/card/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::error::OrNotFound;
use crate::notes::NoteId;
use crate::prelude::TimestampSecs;
use crate::prelude::Usn;
use crate::undo::Op;

impl crate::services::CardsService for Collection {
fn get_card(
Expand Down Expand Up @@ -44,17 +45,20 @@ impl crate::services::CardsService for Collection {
.map(Into::into)
}

fn remove_cards(&mut self, input: anki_proto::cards::RemoveCardsRequest) -> error::Result<()> {
self.transact_no_undo(|col| {
fn remove_cards(
&mut self,
input: anki_proto::cards::RemoveCardsRequest,
) -> error::Result<anki_proto::collection::OpChangesWithCount> {
self.transact(Op::EmptyCards, |col| {
col.remove_cards_and_orphaned_notes(
&input
.card_ids
.into_iter()
.map(Into::into)
.collect::<Vec<_>>(),
)?;
Ok(())
)
})
.map(Into::into)
}

fn set_deck(
Expand Down
2 changes: 2 additions & 0 deletions rslib/src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum Op {
ChangeNotetype,
ClearUnusedTags,
CreateCustomStudy,
EmptyCards,
EmptyFilteredDeck,
FindAndReplace,
ImageOcclusion,
Expand Down Expand Up @@ -57,6 +58,7 @@ impl Op {
Op::AnswerCard => tr.actions_answer_card(),
Op::Bury => tr.studying_bury(),
Op::CreateCustomStudy => tr.actions_custom_study(),
Op::EmptyCards => tr.actions_empty_cards(),
Op::Import => tr.actions_import(),
Op::RemoveDeck => tr.decks_delete_deck(),
Op::RemoveNote => tr.studying_delete_note(),
Expand Down

0 comments on commit 01f4426

Please sign in to comment.