mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
add a separate 'rename deck' method
This commit is contained in:
parent
4bd120cc4b
commit
984e2c2666
7 changed files with 84 additions and 43 deletions
|
@ -250,11 +250,13 @@ class DeckManager:
|
|||
deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn
|
||||
)
|
||||
|
||||
def rename(self, g: Deck, newName: str) -> None:
|
||||
def rename(self, deck: Union[Deck, int], new_name: str) -> None:
|
||||
"Rename deck prefix to NAME if not exists. Updates children."
|
||||
g["name"] = newName
|
||||
self.update(g, preserve_usn=False)
|
||||
return
|
||||
if isinstance(deck, int):
|
||||
deck_id = deck
|
||||
else:
|
||||
deck_id = deck["id"]
|
||||
self.col._backend.rename_deck(deck_id=deck_id, new_name=new_name)
|
||||
|
||||
# Drag/drop
|
||||
#############################################################
|
||||
|
|
|
@ -132,6 +132,7 @@ service DecksService {
|
|||
rpc NewDeckLegacy(Bool) returns (Json);
|
||||
rpc RemoveDeck(DeckID) returns (Empty);
|
||||
rpc DragDropDecks(DragDropDecksIn) returns (Empty);
|
||||
rpc RenameDeck(RenameDeckIn) returns (Empty);
|
||||
}
|
||||
|
||||
service NotesService {
|
||||
|
@ -1448,3 +1449,8 @@ message DeckAndNotetype {
|
|||
int64 deck_id = 1;
|
||||
int64 notetype_id = 2;
|
||||
}
|
||||
|
||||
message RenameDeckIn {
|
||||
int64 deck_id = 1;
|
||||
string new_name = 2;
|
||||
}
|
|
@ -124,4 +124,21 @@ impl DecksService for Backend {
|
|||
self.with_col(|col| col.drag_drop_decks(&source_dids, target_did))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn rename_deck(&self, input: pb::RenameDeckIn) -> Result<pb::Empty> {
|
||||
self.with_col(|col| col.rename_deck(input.deck_id.into(), &input.new_name))
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::DeckId> for DeckID {
|
||||
fn from(did: pb::DeckId) -> Self {
|
||||
DeckID(did.did)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DeckID> for pb::DeckId {
|
||||
fn from(did: DeckID) -> Self {
|
||||
pb::DeckId { did: did.0 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,18 +63,6 @@ impl From<pb::NoteTypeId> for NoteTypeID {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<pb::DeckId> for DeckID {
|
||||
fn from(did: pb::DeckId) -> Self {
|
||||
DeckID(did.did)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DeckID> for pb::DeckId {
|
||||
fn from(did: DeckID) -> Self {
|
||||
pb::DeckId { did: did.0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::DeckConfigId> for DeckConfID {
|
||||
fn from(dcid: pb::DeckConfigId) -> Self {
|
||||
DeckConfID(dcid.dcid)
|
||||
|
|
|
@ -292,32 +292,41 @@ impl Collection {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn update_deck(&mut self, deck: &mut Deck) -> Result<()> {
|
||||
pub fn update_deck(&mut self, deck: &mut Deck) -> Result<()> {
|
||||
self.transact(Some(UndoableOpKind::UpdateDeck), |col| {
|
||||
let usn = col.usn()?;
|
||||
col.prepare_deck_for_update(deck, usn)?;
|
||||
deck.set_modified(usn);
|
||||
if let Some(existing_deck) = col.storage.get_deck(deck.id)? {
|
||||
let name_changed = existing_deck.name != deck.name;
|
||||
if name_changed {
|
||||
// match closest parent name
|
||||
col.match_or_create_parents(deck, usn)?;
|
||||
// rename children
|
||||
col.rename_child_decks(&existing_deck, &deck.name, usn)?;
|
||||
}
|
||||
col.update_single_deck_undoable(deck, &existing_deck)?;
|
||||
if name_changed {
|
||||
// after updating, we need to ensure all grandparents exist, which may not be the case
|
||||
// in the parent->child case
|
||||
col.create_missing_parents(&deck.name, usn)?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AnkiError::invalid_input("updating non-existent deck"))
|
||||
}
|
||||
let existing_deck = col.storage.get_deck(deck.id)?.ok_or(AnkiError::NotFound)?;
|
||||
col.update_deck_inner(deck, existing_deck, col.usn()?)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rename_deck(&mut self, did: DeckID, new_human_name: &str) -> Result<()> {
|
||||
self.transact(Some(UndoableOpKind::RenameDeck), |col| {
|
||||
let existing_deck = col.storage.get_deck(did)?.ok_or(AnkiError::NotFound)?;
|
||||
let mut deck = existing_deck.clone();
|
||||
deck.name = human_deck_name_to_native(new_human_name);
|
||||
col.update_deck_inner(&mut deck, existing_deck, col.usn()?)
|
||||
})
|
||||
}
|
||||
|
||||
fn update_deck_inner(&mut self, deck: &mut Deck, original: Deck, usn: Usn) -> Result<()> {
|
||||
self.prepare_deck_for_update(deck, usn)?;
|
||||
deck.set_modified(usn);
|
||||
let name_changed = original.name != deck.name;
|
||||
if name_changed {
|
||||
// match closest parent name
|
||||
self.match_or_create_parents(deck, usn)?;
|
||||
// rename children
|
||||
self.rename_child_decks(&original, &deck.name, usn)?;
|
||||
}
|
||||
self.update_single_deck_undoable(deck, original)?;
|
||||
if name_changed {
|
||||
// after updating, we need to ensure all grandparents exist, which may not be the case
|
||||
// in the parent->child case
|
||||
self.create_missing_parents(&deck.name, usn)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add/update a single deck when syncing/importing. Ensures name is unique
|
||||
/// & normalized, but does not check parents/children or update mtime
|
||||
/// (unless the name was changed). Caller must set up transaction.
|
||||
|
@ -377,7 +386,7 @@ impl Collection {
|
|||
let new_name = format!("{}\x1f{}", new_name, child_only.join("\x1f"));
|
||||
child.name = new_name;
|
||||
child.set_modified(usn);
|
||||
self.update_single_deck_undoable(&mut child, &original)?;
|
||||
self.update_single_deck_undoable(&mut child, original)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -600,7 +609,7 @@ impl Collection {
|
|||
deck.reset_stats_if_day_changed(today);
|
||||
mutator(&mut deck.common);
|
||||
deck.set_modified(usn);
|
||||
self.update_single_deck_undoable(deck, &original)
|
||||
self.update_single_deck_undoable(deck, original)
|
||||
}
|
||||
|
||||
pub fn drag_drop_decks(
|
||||
|
@ -761,6 +770,23 @@ mod test {
|
|||
col.add_or_update_deck(&mut middle)?;
|
||||
assert_eq!(middle.name, "other+");
|
||||
|
||||
// public function takes human name
|
||||
col.rename_deck(middle.id, "one::two")?;
|
||||
assert_eq!(
|
||||
sorted_names(&col),
|
||||
vec![
|
||||
"Default",
|
||||
"one",
|
||||
"one::two",
|
||||
"one::two::baz",
|
||||
"one::two::baz2",
|
||||
"other",
|
||||
"quux",
|
||||
"quux::foo",
|
||||
"quux::foo::baz",
|
||||
]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ impl Collection {
|
|||
.storage
|
||||
.get_deck(deck.id)?
|
||||
.ok_or_else(|| AnkiError::invalid_input("deck disappeared"))?;
|
||||
self.update_single_deck_undoable(&mut *deck, ¤t)
|
||||
self.update_single_deck_undoable(&mut *deck, current)
|
||||
}
|
||||
UndoableDeckChange::Removed(deck) => self.restore_deleted_deck(*deck),
|
||||
UndoableDeckChange::GraveAdded(e) => self.remove_deck_grave(e.0, e.1),
|
||||
|
@ -52,10 +52,10 @@ impl Collection {
|
|||
pub(super) fn update_single_deck_undoable(
|
||||
&mut self,
|
||||
deck: &mut Deck,
|
||||
original: &Deck,
|
||||
original: Deck,
|
||||
) -> Result<()> {
|
||||
self.state.deck_cache.clear();
|
||||
self.save_undo(UndoableDeckChange::Updated(Box::new(original.clone())));
|
||||
self.save_undo(UndoableDeckChange::Updated(Box::new(original)));
|
||||
self.storage.update_deck(deck)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ pub enum UndoableOpKind {
|
|||
Bury,
|
||||
RemoveDeck,
|
||||
RemoveNote,
|
||||
RenameDeck,
|
||||
Suspend,
|
||||
UnburyUnsuspend,
|
||||
UpdateCard,
|
||||
|
@ -35,6 +36,7 @@ impl Collection {
|
|||
UndoableOpKind::Bury => TR::StudyingBury,
|
||||
UndoableOpKind::RemoveDeck => TR::DecksDeleteDeck,
|
||||
UndoableOpKind::RemoveNote => TR::StudyingDeleteNote,
|
||||
UndoableOpKind::RenameDeck => TR::ActionsRenameDeck,
|
||||
UndoableOpKind::Suspend => TR::StudyingSuspend,
|
||||
UndoableOpKind::UnburyUnsuspend => TR::UndoUnburyUnsuspend,
|
||||
UndoableOpKind::UpdateCard => TR::UndoUpdateCard,
|
||||
|
|
Loading…
Reference in a new issue