From 41779c1aadd6ba10c3ca76c0d337251c0bad2c8f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 4 Mar 2021 21:40:59 +1000 Subject: [PATCH] implement bury/suspend undo --- qt/aqt/browser.py | 4 +- qt/aqt/reviewer.py | 55 ++++++++++--------- rslib/src/backend/mod.rs | 2 +- .../src/{collection.rs => collection/mod.rs} | 9 +-- rslib/src/collection/op.rs | 25 +++++++++ rslib/src/scheduler/answering/undo.rs | 2 +- rslib/src/scheduler/bury_and_suspend.rs | 29 +++++----- rslib/src/scheduler/queue/mod.rs | 9 +-- rslib/src/undo.rs | 9 --- 9 files changed, 82 insertions(+), 62 deletions(-) rename rslib/src/{collection.rs => collection/mod.rs} (97%) create mode 100644 rslib/src/collection/op.rs diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 23703342b..0506ff6ca 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -1262,9 +1262,9 @@ where id in %s""" self.editor.saveNow(self._onSuspend) def _onSuspend(self) -> None: - sus = not self.isSuspended() + want_suspend = not self.isSuspended() c = self.selectedCards() - if sus: + if want_suspend: self.col.sched.suspend_cards(c) else: self.col.sched.unsuspend_cards(c) diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py index 3702d2db5..c54a75237 100644 --- a/qt/aqt/reviewer.py +++ b/qt/aqt/reviewer.py @@ -292,10 +292,10 @@ class Reviewer: ("Ctrl+3", lambda: self.setFlag(3)), ("Ctrl+4", lambda: self.setFlag(4)), ("*", self.onMark), - ("=", self.onBuryNote), - ("-", self.onBuryCard), - ("!", self.onSuspend), - ("@", self.onSuspendCard), + ("=", self.bury_current_note), + ("-", self.bury_current_card), + ("!", self.suspend_current_note), + ("@", self.suspend_current_card), ("Ctrl+Delete", self.onDelete), ("Ctrl+Shift+D", self.on_set_due), ("v", self.onReplayRecorded), @@ -727,11 +727,11 @@ time = %(time)d; ], ], [tr(TR.STUDYING_MARK_NOTE), "*", self.onMark], - [tr(TR.STUDYING_BURY_CARD), "-", self.onBuryCard], - [tr(TR.STUDYING_BURY_NOTE), "=", self.onBuryNote], + [tr(TR.STUDYING_BURY_CARD), "-", self.bury_current_card], + [tr(TR.STUDYING_BURY_NOTE), "=", self.bury_current_note], [tr(TR.ACTIONS_SET_DUE_DATE), "Ctrl+Shift+D", self.on_set_due], - [tr(TR.ACTIONS_SUSPEND_CARD), "@", self.onSuspendCard], - [tr(TR.STUDYING_SUSPEND_NOTE), "!", self.onSuspend], + [tr(TR.ACTIONS_SUSPEND_CARD), "@", self.suspend_current_card], + [tr(TR.STUDYING_SUSPEND_NOTE), "!", self.suspend_current_note], [tr(TR.STUDYING_DELETE_NOTE), "Ctrl+Delete", self.onDelete], [tr(TR.ACTIONS_OPTIONS), "O", self.onOptions], None, @@ -808,17 +808,25 @@ time = %(time)d; on_done=self.mw.reset, ) - def onSuspend(self) -> None: - self.mw.checkpoint(tr(TR.STUDYING_SUSPEND)) + def suspend_current_note(self) -> None: self.mw.col.sched.suspend_cards([c.id for c in self.card.note().cards()]) + self.mw.reset() tooltip(tr(TR.STUDYING_NOTE_SUSPENDED)) - self.mw.reset() - def onSuspendCard(self) -> None: - self.mw.checkpoint(tr(TR.STUDYING_SUSPEND)) + def suspend_current_card(self) -> None: self.mw.col.sched.suspend_cards([self.card.id]) - tooltip(tr(TR.STUDYING_CARD_SUSPENDED)) self.mw.reset() + tooltip(tr(TR.STUDYING_CARD_SUSPENDED)) + + def bury_current_card(self) -> None: + self.mw.col.sched.bury_cards([self.card.id]) + self.mw.reset() + tooltip(tr(TR.STUDYING_CARD_BURIED)) + + def bury_current_note(self) -> None: + self.mw.col.sched.bury_note(self.card.note()) + self.mw.reset() + tooltip(tr(TR.STUDYING_NOTE_BURIED)) def onDelete(self) -> None: # need to check state because the shortcut is global to the main @@ -831,18 +839,6 @@ time = %(time)d; self.mw.reset() tooltip(tr(TR.STUDYING_NOTE_AND_ITS_CARD_DELETED, count=cnt)) - def onBuryCard(self) -> None: - self.mw.checkpoint(tr(TR.STUDYING_BURY)) - self.mw.col.sched.bury_cards([self.card.id]) - self.mw.reset() - tooltip(tr(TR.STUDYING_CARD_BURIED)) - - def onBuryNote(self) -> None: - self.mw.checkpoint(tr(TR.STUDYING_BURY)) - self.mw.col.sched.bury_note(self.card.note()) - self.mw.reset() - tooltip(tr(TR.STUDYING_NOTE_BURIED)) - def onRecordVoice(self) -> None: def after_record(path: str) -> None: self._recordedAudio = path @@ -855,3 +851,10 @@ time = %(time)d; tooltip(tr(TR.STUDYING_YOU_HAVENT_RECORDED_YOUR_VOICE_YET)) return av_player.play_file(self._recordedAudio) + + # legacy + + onBuryCard = bury_current_card + onBuryNote = bury_current_note + onSuspend = suspend_current_note + onSuspendCard = suspend_current_card diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index e90dac1d1..0b9ebcf38 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -707,7 +707,7 @@ impl BackendService for Backend { fn clear_card_queues(&self, _input: pb::Empty) -> BackendResult { self.with_col(|col| { - col.clear_queues(); + col.clear_study_queues(); Ok(().into()) }) } diff --git a/rslib/src/collection.rs b/rslib/src/collection/mod.rs similarity index 97% rename from rslib/src/collection.rs rename to rslib/src/collection/mod.rs index 1ce2253e4..fb8c35b2e 100644 --- a/rslib/src/collection.rs +++ b/rslib/src/collection/mod.rs @@ -1,6 +1,8 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +mod op; + use crate::i18n::I18n; use crate::log::Logger; use crate::types::Usn; @@ -11,6 +13,7 @@ use crate::{ undo::UndoManager, }; use crate::{err::Result, scheduler::queue::CardQueues}; +pub use op::CollectionOp; use std::{collections::HashMap, path::PathBuf, sync::Arc}; pub fn open_collection>( @@ -78,12 +81,6 @@ pub struct Collection { pub(crate) state: CollectionState, } -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum CollectionOp { - UpdateCard, - AnswerCard, -} - impl Collection { /// Execute the provided closure in a transaction, rolling back if /// an error is returned. diff --git a/rslib/src/collection/op.rs b/rslib/src/collection/op.rs new file mode 100644 index 000000000..84e40c71e --- /dev/null +++ b/rslib/src/collection/op.rs @@ -0,0 +1,25 @@ +// 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 CollectionOp { + UpdateCard, + AnswerCard, + Bury, + Suspend, +} + +impl Collection { + pub fn describe_collection_op(&self, op: CollectionOp) -> String { + let key = match op { + CollectionOp::UpdateCard => todo!(), + CollectionOp::AnswerCard => TR::UndoAnswerCard, + CollectionOp::Bury => TR::StudyingBury, + CollectionOp::Suspend => TR::StudyingSuspend, + }; + + self.i18n.tr(key).to_string() + } +} diff --git a/rslib/src/scheduler/answering/undo.rs b/rslib/src/scheduler/answering/undo.rs index dc9ef5824..7dda96710 100644 --- a/rslib/src/scheduler/answering/undo.rs +++ b/rslib/src/scheduler/answering/undo.rs @@ -66,7 +66,7 @@ mod test { col.storage.update_card(&card)?; // fail it, which should cause it to be marked as a leech - col.clear_queues(); + col.clear_study_queues(); let queued = col.next_card()?.unwrap(); dbg!(&queued); col.answer_card(&CardAnswer { diff --git a/rslib/src/scheduler/bury_and_suspend.rs b/rslib/src/scheduler/bury_and_suspend.rs index 109176732..2d5af0c43 100644 --- a/rslib/src/scheduler/bury_and_suspend.rs +++ b/rslib/src/scheduler/bury_and_suspend.rs @@ -12,7 +12,10 @@ use crate::{ }; use super::timing::SchedTimingToday; -use pb::unbury_cards_in_current_deck_in::Mode as UnburyDeckMode; +use pb::{ + bury_or_suspend_cards_in::Mode as BuryOrSuspendMode, + unbury_cards_in_current_deck_in::Mode as UnburyDeckMode, +}; impl Card { /// True if card was buried/suspended prior to the call. @@ -86,20 +89,16 @@ impl Collection { /// Bury/suspend cards in search table, and clear it. /// Marks the cards as modified. - fn bury_or_suspend_searched_cards( - &mut self, - mode: pb::bury_or_suspend_cards_in::Mode, - ) -> Result<()> { - use pb::bury_or_suspend_cards_in::Mode; + fn bury_or_suspend_searched_cards(&mut self, mode: BuryOrSuspendMode) -> Result<()> { let usn = self.usn()?; let sched = self.scheduler_version(); for original in self.storage.all_searched_cards()? { let mut card = original.clone(); let desired_queue = match mode { - Mode::Suspend => CardQueue::Suspended, - Mode::BurySched => CardQueue::SchedBuried, - Mode::BuryUser => { + BuryOrSuspendMode::Suspend => CardQueue::Suspended, + BuryOrSuspendMode::BurySched => CardQueue::SchedBuried, + BuryOrSuspendMode::BuryUser => { if sched == SchedulerVersion::V1 { // v1 scheduler only had one bury type CardQueue::SchedBuried @@ -124,9 +123,14 @@ impl Collection { pub fn bury_or_suspend_cards( &mut self, cids: &[CardID], - mode: pb::bury_or_suspend_cards_in::Mode, + mode: BuryOrSuspendMode, ) -> Result<()> { - self.transact(None, |col| { + let op = match mode { + BuryOrSuspendMode::Suspend => CollectionOp::Suspend, + BuryOrSuspendMode::BurySched | BuryOrSuspendMode::BuryUser => CollectionOp::Bury, + }; + self.transact(Some(op), |col| { + col.clear_study_queues(); col.storage.set_search_table_to_card_ids(cids, false)?; col.bury_or_suspend_searched_cards(mode) }) @@ -139,10 +143,9 @@ impl Collection { include_new: bool, include_reviews: bool, ) -> Result<()> { - use pb::bury_or_suspend_cards_in::Mode; self.storage .search_siblings_for_bury(cid, nid, include_new, include_reviews)?; - self.bury_or_suspend_searched_cards(Mode::BurySched) + self.bury_or_suspend_searched_cards(BuryOrSuspendMode::BurySched) } } diff --git a/rslib/src/scheduler/queue/mod.rs b/rslib/src/scheduler/queue/mod.rs index 4967c1653..2a3146255 100644 --- a/rslib/src/scheduler/queue/mod.rs +++ b/rslib/src/scheduler/queue/mod.rs @@ -132,11 +132,12 @@ impl Collection { } } - pub(crate) fn clear_queues(&mut self) { - // clearing the queue will remove any undone reviews from the undo queue, - // causing problems if we then try to redo them - self.state.undo.clear_redo(); + pub(crate) fn clear_study_queues(&mut self) { self.state.card_queues = None; + // clearing the queue will remove any undone reviews from the undo queue, + // causing problems if we then try to redo them, so we need to clear the + // redo queue as well + self.state.undo.clear_redo(); } pub(crate) fn update_queues_after_answering_card( diff --git a/rslib/src/undo.rs b/rslib/src/undo.rs index ffc68298b..490b05ab7 100644 --- a/rslib/src/undo.rs +++ b/rslib/src/undo.rs @@ -2,7 +2,6 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html use crate::backend_proto as pb; -use crate::i18n::TR; use crate::{ collection::{Collection, CollectionOp}, err::Result, @@ -145,14 +144,6 @@ impl Collection { self.state.undo.save(item) } - pub fn describe_collection_op(&self, op: CollectionOp) -> String { - match op { - CollectionOp::UpdateCard => todo!(), - CollectionOp::AnswerCard => self.i18n.tr(TR::UndoAnswerCard), - } - .to_string() - } - pub fn undo_status(&self) -> pb::UndoStatus { pb::UndoStatus { undo: self