move ops.rs out of undo/
This commit is contained in:
parent
8fc43956c2
commit
90526c61cd
@ -26,7 +26,7 @@ impl CardsService for Backend {
|
||||
let op = if input.skip_undo_entry {
|
||||
None
|
||||
} else {
|
||||
Some(UndoableOpKind::UpdateCard)
|
||||
Some(Op::UpdateCard)
|
||||
};
|
||||
let mut card: Card = input.card.ok_or(AnkiError::NotFound)?.try_into()?;
|
||||
col.update_card_with_op(&mut card, op)
|
||||
|
@ -51,7 +51,7 @@ impl NotesService for Backend {
|
||||
let op = if input.skip_undo_entry {
|
||||
None
|
||||
} else {
|
||||
Some(UndoableOpKind::UpdateNote)
|
||||
Some(Op::UpdateNote)
|
||||
};
|
||||
let mut note: Note = input.note.ok_or(AnkiError::NotFound)?.into();
|
||||
col.update_note_with_op(&mut note, op)
|
||||
|
@ -3,12 +3,13 @@
|
||||
|
||||
pub(crate) mod undo;
|
||||
|
||||
use crate::define_newtype;
|
||||
use crate::err::{AnkiError, Result};
|
||||
use crate::notes::NoteID;
|
||||
use crate::{
|
||||
collection::Collection, config::SchedulerVersion, timestamp::TimestampSecs, types::Usn,
|
||||
collection::Collection, config::SchedulerVersion, prelude::*, timestamp::TimestampSecs,
|
||||
types::Usn,
|
||||
};
|
||||
use crate::{define_newtype, undo::UndoableOpKind};
|
||||
|
||||
use crate::{deckconf::DeckConf, decks::DeckID};
|
||||
use num_enum::TryFromPrimitive;
|
||||
@ -139,11 +140,7 @@ impl Card {
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub(crate) fn update_card_with_op(
|
||||
&mut self,
|
||||
card: &mut Card,
|
||||
op: Option<UndoableOpKind>,
|
||||
) -> Result<()> {
|
||||
pub(crate) fn update_card_with_op(&mut self, card: &mut Card, op: Option<Op>) -> Result<()> {
|
||||
let existing = self.storage.get_card(card.id)?.ok_or(AnkiError::NotFound)?;
|
||||
self.transact(op, |col| col.update_card_inner(card, existing, col.usn()?))
|
||||
}
|
||||
@ -211,7 +208,7 @@ impl Collection {
|
||||
self.storage.set_search_table_to_card_ids(cards, false)?;
|
||||
let sched = self.scheduler_version();
|
||||
let usn = self.usn()?;
|
||||
self.transact(Some(UndoableOpKind::SetDeck), |col| {
|
||||
self.transact(Some(Op::SetDeck), |col| {
|
||||
for mut card in col.storage.all_searched_cards()? {
|
||||
if card.deck_id == deck_id {
|
||||
continue;
|
||||
|
@ -85,7 +85,7 @@ pub struct Collection {
|
||||
impl Collection {
|
||||
/// Execute the provided closure in a transaction, rolling back if
|
||||
/// an error is returned.
|
||||
pub(crate) fn transact<F, R>(&mut self, op: Option<UndoableOpKind>, func: F) -> Result<R>
|
||||
pub(crate) fn transact<F, R>(&mut self, op: Option<Op>, func: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&mut Collection) -> Result<R>,
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ mod test {
|
||||
fn undo() -> Result<()> {
|
||||
let mut col = open_test_collection();
|
||||
// the op kind doesn't matter, we just need undo enabled
|
||||
let op = Some(UndoableOpKind::Bury);
|
||||
let op = Some(Op::Bury);
|
||||
// test key
|
||||
let key = BoolKey::NormalizeNoteText;
|
||||
|
||||
|
@ -10,16 +10,14 @@ pub use crate::backend_proto::{
|
||||
deck_kind::Kind as DeckKind, filtered_search_term::FilteredSearchOrder, Deck as DeckProto,
|
||||
DeckCommon, DeckKind as DeckKindProto, FilteredDeck, FilteredSearchTerm, NormalDeck,
|
||||
};
|
||||
use crate::{
|
||||
backend_proto as pb, markdown::render_markdown, text::sanitize_html_no_images,
|
||||
undo::UndoableOpKind,
|
||||
};
|
||||
use crate::{backend_proto as pb, markdown::render_markdown, text::sanitize_html_no_images};
|
||||
use crate::{
|
||||
collection::Collection,
|
||||
deckconf::DeckConfID,
|
||||
define_newtype,
|
||||
err::{AnkiError, Result},
|
||||
i18n::TR,
|
||||
prelude::*,
|
||||
text::normalize_to_nfc,
|
||||
timestamp::TimestampSecs,
|
||||
types::Usn,
|
||||
@ -283,7 +281,7 @@ impl Collection {
|
||||
return Err(AnkiError::invalid_input("deck to add must have id 0"));
|
||||
}
|
||||
|
||||
self.transact(Some(UndoableOpKind::AddDeck), |col| {
|
||||
self.transact(Some(Op::AddDeck), |col| {
|
||||
let usn = col.usn()?;
|
||||
col.prepare_deck_for_update(deck, usn)?;
|
||||
deck.set_modified(usn);
|
||||
@ -293,14 +291,14 @@ impl Collection {
|
||||
}
|
||||
|
||||
pub fn update_deck(&mut self, deck: &mut Deck) -> Result<()> {
|
||||
self.transact(Some(UndoableOpKind::UpdateDeck), |col| {
|
||||
self.transact(Some(Op::UpdateDeck), |col| {
|
||||
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| {
|
||||
self.transact(Some(Op::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);
|
||||
@ -468,7 +466,7 @@ impl Collection {
|
||||
|
||||
pub fn remove_decks_and_child_decks(&mut self, dids: &[DeckID]) -> Result<usize> {
|
||||
let mut card_count = 0;
|
||||
self.transact(Some(UndoableOpKind::RemoveDeck), |col| {
|
||||
self.transact(Some(Op::RemoveDeck), |col| {
|
||||
let usn = col.usn()?;
|
||||
for did in dids {
|
||||
if let Some(deck) = col.storage.get_deck(*did)? {
|
||||
@ -627,7 +625,7 @@ impl Collection {
|
||||
target: Option<DeckID>,
|
||||
) -> Result<()> {
|
||||
let usn = self.usn()?;
|
||||
self.transact(Some(UndoableOpKind::RenameDeck), |col| {
|
||||
self.transact(Some(Op::RenameDeck), |col| {
|
||||
let target_deck;
|
||||
let mut target_name = None;
|
||||
if let Some(target) = target {
|
||||
|
@ -24,6 +24,7 @@ mod markdown;
|
||||
pub mod media;
|
||||
pub mod notes;
|
||||
pub mod notetype;
|
||||
pub mod ops;
|
||||
mod preferences;
|
||||
pub mod prelude;
|
||||
pub mod revlog;
|
||||
|
@ -306,7 +306,7 @@ impl Collection {
|
||||
}
|
||||
|
||||
pub fn add_note(&mut self, note: &mut Note, did: DeckID) -> Result<()> {
|
||||
self.transact(Some(UndoableOpKind::AddNote), |col| {
|
||||
self.transact(Some(Op::AddNote), |col| {
|
||||
let nt = col
|
||||
.get_notetype(note.notetype_id)?
|
||||
.ok_or_else(|| AnkiError::invalid_input("missing note type"))?;
|
||||
@ -335,14 +335,10 @@ impl Collection {
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn update_note(&mut self, note: &mut Note) -> Result<()> {
|
||||
self.update_note_with_op(note, Some(UndoableOpKind::UpdateNote))
|
||||
self.update_note_with_op(note, Some(Op::UpdateNote))
|
||||
}
|
||||
|
||||
pub(crate) fn update_note_with_op(
|
||||
&mut self,
|
||||
note: &mut Note,
|
||||
op: Option<UndoableOpKind>,
|
||||
) -> Result<()> {
|
||||
pub(crate) fn update_note_with_op(&mut self, note: &mut Note, op: Option<Op>) -> Result<()> {
|
||||
let mut existing_note = self.storage.get_note(note.id)?.ok_or(AnkiError::NotFound)?;
|
||||
if !note_differs_from_db(&mut existing_note, note) {
|
||||
// nothing to do
|
||||
@ -398,7 +394,7 @@ impl Collection {
|
||||
/// Remove provided notes, and any cards that use them.
|
||||
pub(crate) fn remove_notes(&mut self, nids: &[NoteID]) -> Result<()> {
|
||||
let usn = self.usn()?;
|
||||
self.transact(Some(UndoableOpKind::RemoveNote), |col| {
|
||||
self.transact(Some(Op::RemoveNote), |col| {
|
||||
for nid in nids {
|
||||
let nid = *nid;
|
||||
if let Some(_existing_note) = col.storage.get_note(nid)? {
|
||||
|
@ -96,7 +96,7 @@ impl Collection {
|
||||
op.changes.last()
|
||||
{
|
||||
note.id == before_change.id
|
||||
&& op.kind == UndoableOpKind::UpdateNote
|
||||
&& op.kind == Op::UpdateNote
|
||||
&& op.timestamp.elapsed_secs() < 60
|
||||
} else {
|
||||
false
|
||||
|
57
rslib/src/ops.rs
Normal file
57
rslib/src/ops.rs
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Op {
|
||||
AddDeck,
|
||||
AddNote,
|
||||
AnswerCard,
|
||||
Bury,
|
||||
RemoveDeck,
|
||||
RemoveNote,
|
||||
RenameDeck,
|
||||
ScheduleAsNew,
|
||||
SetDueDate,
|
||||
Suspend,
|
||||
UnburyUnsuspend,
|
||||
UpdateCard,
|
||||
UpdateDeck,
|
||||
UpdateNote,
|
||||
UpdatePreferences,
|
||||
UpdateTag,
|
||||
SetDeck,
|
||||
}
|
||||
|
||||
impl Op {
|
||||
pub(crate) fn needs_study_queue_reset(self) -> bool {
|
||||
self != Op::AnswerCard
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub fn describe_op_kind(&self, op: Op) -> String {
|
||||
let key = match op {
|
||||
Op::AddDeck => TR::UndoAddDeck,
|
||||
Op::AddNote => TR::UndoAddNote,
|
||||
Op::AnswerCard => TR::UndoAnswerCard,
|
||||
Op::Bury => TR::StudyingBury,
|
||||
Op::RemoveDeck => TR::DecksDeleteDeck,
|
||||
Op::RemoveNote => TR::StudyingDeleteNote,
|
||||
Op::RenameDeck => TR::ActionsRenameDeck,
|
||||
Op::ScheduleAsNew => TR::UndoForgetCard,
|
||||
Op::SetDueDate => TR::ActionsSetDueDate,
|
||||
Op::Suspend => TR::StudyingSuspend,
|
||||
Op::UnburyUnsuspend => TR::UndoUnburyUnsuspend,
|
||||
Op::UpdateCard => TR::UndoUpdateCard,
|
||||
Op::UpdateDeck => TR::UndoUpdateDeck,
|
||||
Op::UpdateNote => TR::UndoUpdateNote,
|
||||
Op::UpdatePreferences => TR::PreferencesPreferences,
|
||||
Op::UpdateTag => TR::UndoUpdateTag,
|
||||
Op::SetDeck => TR::BrowsingChangeDeck,
|
||||
};
|
||||
|
||||
self.i18n.tr(key).to_string()
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ use crate::{
|
||||
collection::Collection,
|
||||
config::BoolKey,
|
||||
err::Result,
|
||||
prelude::*,
|
||||
scheduler::timing::local_minutes_west_for_stamp,
|
||||
};
|
||||
|
||||
@ -23,10 +24,9 @@ impl Collection {
|
||||
}
|
||||
|
||||
pub fn set_preferences(&mut self, prefs: Preferences) -> Result<()> {
|
||||
self.transact(
|
||||
Some(crate::undo::UndoableOpKind::UpdatePreferences),
|
||||
|col| col.set_preferences_inner(prefs),
|
||||
)
|
||||
self.transact(Some(Op::UpdatePreferences), |col| {
|
||||
col.set_preferences_inner(prefs)
|
||||
})
|
||||
}
|
||||
|
||||
fn set_preferences_inner(
|
||||
|
@ -11,9 +11,9 @@ pub use crate::{
|
||||
i18n::{tr_args, tr_strs, I18n, TR},
|
||||
notes::{Note, NoteID},
|
||||
notetype::{NoteType, NoteTypeID},
|
||||
ops::Op,
|
||||
revlog::RevlogID,
|
||||
timestamp::{TimestampMillis, TimestampSecs},
|
||||
types::Usn,
|
||||
undo::UndoableOpKind,
|
||||
};
|
||||
pub use slog::{debug, Logger};
|
||||
|
@ -241,9 +241,7 @@ impl Collection {
|
||||
|
||||
/// Answer card, writing its new state to the database.
|
||||
pub fn answer_card(&mut self, answer: &CardAnswer) -> Result<()> {
|
||||
self.transact(Some(UndoableOpKind::AnswerCard), |col| {
|
||||
col.answer_card_inner(answer)
|
||||
})
|
||||
self.transact(Some(Op::AnswerCard), |col| col.answer_card_inner(answer))
|
||||
}
|
||||
|
||||
fn answer_card_inner(&mut self, answer: &CardAnswer) -> Result<()> {
|
||||
|
@ -69,7 +69,7 @@ impl Collection {
|
||||
}
|
||||
|
||||
pub fn unbury_or_unsuspend_cards(&mut self, cids: &[CardID]) -> Result<()> {
|
||||
self.transact(Some(UndoableOpKind::UnburyUnsuspend), |col| {
|
||||
self.transact(Some(Op::UnburyUnsuspend), |col| {
|
||||
col.storage.set_search_table_to_card_ids(cids, false)?;
|
||||
col.unsuspend_or_unbury_searched_cards()
|
||||
})
|
||||
@ -126,8 +126,8 @@ impl Collection {
|
||||
mode: BuryOrSuspendMode,
|
||||
) -> Result<()> {
|
||||
let op = match mode {
|
||||
BuryOrSuspendMode::Suspend => UndoableOpKind::Suspend,
|
||||
BuryOrSuspendMode::BurySched | BuryOrSuspendMode::BuryUser => UndoableOpKind::Bury,
|
||||
BuryOrSuspendMode::Suspend => Op::Suspend,
|
||||
BuryOrSuspendMode::BurySched | BuryOrSuspendMode::BuryUser => Op::Bury,
|
||||
};
|
||||
self.transact(Some(op), |col| {
|
||||
col.storage.set_search_table_to_card_ids(cids, false)?;
|
||||
|
@ -7,9 +7,9 @@ use crate::{
|
||||
decks::DeckID,
|
||||
err::Result,
|
||||
notes::NoteID,
|
||||
prelude::*,
|
||||
search::SortMode,
|
||||
types::Usn,
|
||||
undo::UndoableOpKind,
|
||||
};
|
||||
use rand::seq::SliceRandom;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@ -106,7 +106,7 @@ impl Collection {
|
||||
pub fn reschedule_cards_as_new(&mut self, cids: &[CardID], log: bool) -> Result<()> {
|
||||
let usn = self.usn()?;
|
||||
let mut position = self.get_next_card_position();
|
||||
self.transact(Some(UndoableOpKind::ScheduleAsNew), |col| {
|
||||
self.transact(Some(Op::ScheduleAsNew), |col| {
|
||||
col.storage.set_search_table_to_card_ids(cids, true)?;
|
||||
let cards = col.storage.all_searched_cards_in_search_order()?;
|
||||
for mut card in cards {
|
||||
|
@ -7,8 +7,7 @@ use crate::{
|
||||
config::StringKey,
|
||||
deckconf::INITIAL_EASE_FACTOR_THOUSANDS,
|
||||
err::Result,
|
||||
prelude::AnkiError,
|
||||
undo::UndoableOpKind,
|
||||
prelude::*,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
@ -100,7 +99,7 @@ impl Collection {
|
||||
let today = self.timing_today()?.days_elapsed;
|
||||
let mut rng = rand::thread_rng();
|
||||
let distribution = Uniform::from(spec.min..=spec.max);
|
||||
self.transact(Some(UndoableOpKind::SetDueDate), |col| {
|
||||
self.transact(Some(Op::SetDueDate), |col| {
|
||||
col.storage.set_search_table_to_card_ids(cids, false)?;
|
||||
for mut card in col.storage.all_searched_cards()? {
|
||||
let original = card.clone();
|
||||
|
@ -341,7 +341,7 @@ impl Collection {
|
||||
tags: &[Regex],
|
||||
mut repl: R,
|
||||
) -> Result<usize> {
|
||||
self.transact(Some(UndoableOpKind::UpdateTag), |col| {
|
||||
self.transact(Some(Op::UpdateTag), |col| {
|
||||
col.transform_notes(nids, |note, _nt| {
|
||||
let mut changed = false;
|
||||
for re in tags {
|
||||
@ -392,7 +392,7 @@ impl Collection {
|
||||
)
|
||||
.map_err(|_| AnkiError::invalid_input("invalid regex"))?;
|
||||
|
||||
self.transact(Some(UndoableOpKind::UpdateTag), |col| {
|
||||
self.transact(Some(Op::UpdateTag), |col| {
|
||||
col.transform_notes(nids, |note, _nt| {
|
||||
let mut need_to_add = true;
|
||||
let mut match_count = 0;
|
||||
|
@ -2,10 +2,9 @@
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
mod changes;
|
||||
mod ops;
|
||||
|
||||
pub use crate::ops::Op;
|
||||
pub(crate) use changes::UndoableChange;
|
||||
pub use ops::UndoableOpKind;
|
||||
|
||||
use crate::backend_proto as pb;
|
||||
use crate::prelude::*;
|
||||
@ -15,7 +14,7 @@ const UNDO_LIMIT: usize = 30;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UndoableOp {
|
||||
pub kind: UndoableOpKind,
|
||||
pub kind: Op,
|
||||
pub timestamp: TimestampSecs,
|
||||
pub changes: Vec<UndoableChange>,
|
||||
}
|
||||
@ -51,7 +50,7 @@ impl UndoManager {
|
||||
}
|
||||
}
|
||||
|
||||
fn begin_step(&mut self, op: Option<UndoableOpKind>) {
|
||||
fn begin_step(&mut self, op: Option<Op>) {
|
||||
println!("begin: {:?}", op);
|
||||
if op.is_none() {
|
||||
self.undo_steps.clear();
|
||||
@ -88,11 +87,11 @@ impl UndoManager {
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn can_undo(&self) -> Option<UndoableOpKind> {
|
||||
fn can_undo(&self) -> Option<Op> {
|
||||
self.undo_steps.front().map(|s| s.kind)
|
||||
}
|
||||
|
||||
fn can_redo(&self) -> Option<UndoableOpKind> {
|
||||
fn can_redo(&self) -> Option<Op> {
|
||||
self.redo_steps.last().map(|s| s.kind)
|
||||
}
|
||||
|
||||
@ -102,11 +101,11 @@ impl UndoManager {
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub fn can_undo(&self) -> Option<UndoableOpKind> {
|
||||
pub fn can_undo(&self) -> Option<Op> {
|
||||
self.state.undo.can_undo()
|
||||
}
|
||||
|
||||
pub fn can_redo(&self) -> Option<UndoableOpKind> {
|
||||
pub fn can_redo(&self) -> Option<Op> {
|
||||
self.state.undo.can_redo()
|
||||
}
|
||||
|
||||
@ -156,7 +155,7 @@ impl Collection {
|
||||
}
|
||||
|
||||
/// If op is None, clears the undo/redo queues.
|
||||
pub(crate) fn begin_undoable_operation(&mut self, op: Option<UndoableOpKind>) {
|
||||
pub(crate) fn begin_undoable_operation(&mut self, op: Option<Op>) {
|
||||
self.state.undo.begin_step(op);
|
||||
}
|
||||
|
||||
@ -219,7 +218,7 @@ mod test {
|
||||
|
||||
// record a few undo steps
|
||||
for i in 3..=4 {
|
||||
col.transact(Some(UndoableOpKind::UpdateCard), |col| {
|
||||
col.transact(Some(Op::UpdateCard), |col| {
|
||||
col.get_and_update_card(cid, |card| {
|
||||
card.interval = i;
|
||||
Ok(())
|
||||
@ -231,41 +230,41 @@ mod test {
|
||||
}
|
||||
|
||||
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 4);
|
||||
assert_eq!(col.can_undo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_undo(), Some(Op::UpdateCard));
|
||||
assert_eq!(col.can_redo(), None);
|
||||
|
||||
// undo a step
|
||||
col.undo().unwrap();
|
||||
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 3);
|
||||
assert_eq!(col.can_undo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_redo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_undo(), Some(Op::UpdateCard));
|
||||
assert_eq!(col.can_redo(), Some(Op::UpdateCard));
|
||||
|
||||
// and again
|
||||
col.undo().unwrap();
|
||||
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 2);
|
||||
assert_eq!(col.can_undo(), None);
|
||||
assert_eq!(col.can_redo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_redo(), Some(Op::UpdateCard));
|
||||
|
||||
// redo a step
|
||||
col.redo().unwrap();
|
||||
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 3);
|
||||
assert_eq!(col.can_undo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_redo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_undo(), Some(Op::UpdateCard));
|
||||
assert_eq!(col.can_redo(), Some(Op::UpdateCard));
|
||||
|
||||
// and another
|
||||
col.redo().unwrap();
|
||||
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 4);
|
||||
assert_eq!(col.can_undo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_undo(), Some(Op::UpdateCard));
|
||||
assert_eq!(col.can_redo(), None);
|
||||
|
||||
// and undo the redo
|
||||
col.undo().unwrap();
|
||||
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 3);
|
||||
assert_eq!(col.can_undo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_redo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_undo(), Some(Op::UpdateCard));
|
||||
assert_eq!(col.can_redo(), Some(Op::UpdateCard));
|
||||
|
||||
// if any action is performed, it should clear the redo queue
|
||||
col.transact(Some(UndoableOpKind::UpdateCard), |col| {
|
||||
col.transact(Some(Op::UpdateCard), |col| {
|
||||
col.get_and_update_card(cid, |card| {
|
||||
card.interval = 5;
|
||||
Ok(())
|
||||
@ -275,7 +274,7 @@ mod test {
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 5);
|
||||
assert_eq!(col.can_undo(), Some(UndoableOpKind::UpdateCard));
|
||||
assert_eq!(col.can_undo(), Some(Op::UpdateCard));
|
||||
assert_eq!(col.can_redo(), None);
|
||||
|
||||
// and any action that doesn't support undoing will clear both queues
|
||||
|
@ -1,57 +0,0 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum UndoableOpKind {
|
||||
AddDeck,
|
||||
AddNote,
|
||||
AnswerCard,
|
||||
Bury,
|
||||
RemoveDeck,
|
||||
RemoveNote,
|
||||
RenameDeck,
|
||||
ScheduleAsNew,
|
||||
SetDueDate,
|
||||
Suspend,
|
||||
UnburyUnsuspend,
|
||||
UpdateCard,
|
||||
UpdateDeck,
|
||||
UpdateNote,
|
||||
UpdatePreferences,
|
||||
UpdateTag,
|
||||
SetDeck,
|
||||
}
|
||||
|
||||
impl UndoableOpKind {
|
||||
pub(crate) fn needs_study_queue_reset(self) -> bool {
|
||||
self != UndoableOpKind::AnswerCard
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub fn describe_op_kind(&self, op: UndoableOpKind) -> String {
|
||||
let key = match op {
|
||||
UndoableOpKind::AddDeck => TR::UndoAddDeck,
|
||||
UndoableOpKind::AddNote => TR::UndoAddNote,
|
||||
UndoableOpKind::AnswerCard => TR::UndoAnswerCard,
|
||||
UndoableOpKind::Bury => TR::StudyingBury,
|
||||
UndoableOpKind::RemoveDeck => TR::DecksDeleteDeck,
|
||||
UndoableOpKind::RemoveNote => TR::StudyingDeleteNote,
|
||||
UndoableOpKind::RenameDeck => TR::ActionsRenameDeck,
|
||||
UndoableOpKind::ScheduleAsNew => TR::UndoForgetCard,
|
||||
UndoableOpKind::SetDueDate => TR::ActionsSetDueDate,
|
||||
UndoableOpKind::Suspend => TR::StudyingSuspend,
|
||||
UndoableOpKind::UnburyUnsuspend => TR::UndoUnburyUnsuspend,
|
||||
UndoableOpKind::UpdateCard => TR::UndoUpdateCard,
|
||||
UndoableOpKind::UpdateDeck => TR::UndoUpdateDeck,
|
||||
UndoableOpKind::UpdateNote => TR::UndoUpdateNote,
|
||||
UndoableOpKind::UpdatePreferences => TR::PreferencesPreferences,
|
||||
UndoableOpKind::UpdateTag => TR::UndoUpdateTag,
|
||||
UndoableOpKind::SetDeck => TR::BrowsingChangeDeck,
|
||||
};
|
||||
|
||||
self.i18n.tr(key).to_string()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user