diff --git a/rslib/backend.proto b/rslib/backend.proto index 7ffc67010..494cd10f2 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -1442,9 +1442,22 @@ message GetQueuedCardsOut { } } +message StateChanges { + bool card_added = 1; + bool card_modified = 2; + bool note_added = 3; + bool note_modified = 4; + bool deck_added = 5; + bool deck_modified = 6; + bool tag_modified = 7; + bool notetype_modified = 8; + bool preference_modified = 9; +} + message UndoStatus { string undo = 1; string redo = 2; + StateChanges changes = 3; } message DefaultsForAddingIn { diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index a13cb88f9..7c1521260 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -15,6 +15,7 @@ mod i18n; mod media; mod notes; mod notetypes; +mod ops; mod progress; mod scheduler; mod search; diff --git a/rslib/src/backend/ops.rs b/rslib/src/backend/ops.rs new file mode 100644 index 000000000..d1d99eaa1 --- /dev/null +++ b/rslib/src/backend/ops.rs @@ -0,0 +1,20 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +use crate::{backend_proto as pb, ops::StateChanges}; + +impl From for pb::StateChanges { + fn from(c: StateChanges) -> Self { + pb::StateChanges { + card_added: c.card_added, + card_modified: c.card_modified, + note_added: c.note_added, + note_modified: c.note_modified, + deck_added: c.deck_added, + deck_modified: c.deck_modified, + tag_modified: c.tag_modified, + notetype_modified: c.notetype_modified, + preference_modified: c.preference_modified, + } + } +} diff --git a/rslib/src/ops.rs b/rslib/src/ops.rs index 47330406c..5d5b50416 100644 --- a/rslib/src/ops.rs +++ b/rslib/src/ops.rs @@ -25,8 +25,78 @@ pub enum Op { } impl Op { + /// Used internally to decide whether the study queues need to be invalidated. pub(crate) fn needs_study_queue_reset(self) -> bool { + let changes = self.state_changes(); self != Op::AnswerCard + && (changes.card_added + || changes.card_modified + || changes.deck_modified + || changes.preference_modified) + } + + pub fn state_changes(self) -> StateChanges { + let default = Default::default; + match self { + Op::ScheduleAsNew + | Op::SetDueDate + | Op::Suspend + | Op::UnburyUnsuspend + | Op::UpdateCard + | Op::SetDeck + | Op::Bury => StateChanges { + card_modified: true, + ..default() + }, + Op::AnswerCard => StateChanges { + card_modified: true, + // this also modifies the daily counts stored in the + // deck, but the UI does not care about that + ..default() + }, + Op::AddDeck => StateChanges { + deck_added: true, + ..default() + }, + Op::AddNote => StateChanges { + card_added: true, + note_added: true, + ..default() + }, + Op::RemoveDeck => StateChanges { + card_modified: true, + note_modified: true, + deck_modified: true, + ..default() + }, + Op::RemoveNote => StateChanges { + card_modified: true, + note_modified: true, + ..default() + }, + Op::RenameDeck => StateChanges { + deck_modified: true, + ..default() + }, + Op::UpdateDeck => StateChanges { + deck_modified: true, + ..default() + }, + Op::UpdateNote => StateChanges { + note_modified: true, + // edits may result in new cards being generated + card_added: true, + ..default() + }, + Op::UpdatePreferences => StateChanges { + preference_modified: true, + ..default() + }, + Op::UpdateTag => StateChanges { + tag_modified: true, + ..default() + }, + } } } @@ -55,3 +125,16 @@ impl Collection { self.i18n.tr(key).to_string() } } + +#[derive(Debug, Default, Clone, Copy)] +pub struct StateChanges { + pub card_added: bool, + pub card_modified: bool, + pub note_added: bool, + pub note_modified: bool, + pub deck_added: bool, + pub deck_modified: bool, + pub tag_modified: bool, + pub notetype_modified: bool, + pub preference_modified: bool, +} diff --git a/rslib/src/undo/mod.rs b/rslib/src/undo/mod.rs index 917b10cad..75fd90208 100644 --- a/rslib/src/undo/mod.rs +++ b/rslib/src/undo/mod.rs @@ -151,6 +151,12 @@ impl Collection { .can_redo() .map(|op| self.describe_op_kind(op)) .unwrap_or_default(), + changes: Some( + self.can_undo() + .map(|op| op.state_changes()) + .unwrap_or_default() + .into(), + ), } }