Anki/rslib/src/ops.rs
Damien Elmes f3e81c8a95 Move custom study tag and limit gathering+saving into the backend
Ideally this would have been in beta 6 :-) No add-ons appear to be
using customstudy.py/taglimit.py though, so it should hopefully not be
disruptive.

In the earlier custom study changes, we didn't get around to addressing
issue #1136. Now instead of trying to determine the maximum increase
to allow (which doesn't work correctly with nested decks), we just
present the total available to the user again, and let them decide. There's
plenty of room for improvement here still, but further work here might
be better done once we look into decoupling deck limits from deck presets.

Tags and available cards are fetched prior to showing the dialog now,
and will show a progress dialog if things take a while.

Tags are stored in an aux var now, so they don't inflate the deck
object size.
2022-03-10 16:23:03 +10:00

165 lines
5 KiB
Rust

// 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, PartialEq)]
pub enum Op {
Custom(String),
AddDeck,
AddNote,
AddNotetype,
AnswerCard,
BuildFilteredDeck,
Bury,
ChangeNotetype,
ClearUnusedTags,
CreateCustomStudy,
EmptyFilteredDeck,
FindAndReplace,
RebuildFilteredDeck,
RemoveDeck,
RemoveNote,
RemoveNotetype,
RemoveTag,
RenameDeck,
ReparentDeck,
RenameTag,
ReparentTag,
ScheduleAsNew,
SetCardDeck,
SetDueDate,
SetFlag,
SortCards,
Suspend,
UnburyUnsuspend,
UpdateCard,
UpdateConfig,
UpdateDeck,
UpdateDeckConfig,
UpdateNote,
UpdatePreferences,
UpdateTag,
UpdateNotetype,
SetCurrentDeck,
/// Does not register changes in undo queue, but does not clear the current
/// queue either.
SkipUndo,
}
impl Op {
pub fn describe(&self, tr: &I18n) -> String {
match self {
Op::AddDeck => tr.actions_add_deck(),
Op::AddNote => tr.actions_add_note(),
Op::AnswerCard => tr.actions_answer_card(),
Op::Bury => tr.studying_bury(),
Op::CreateCustomStudy => tr.actions_custom_study(),
Op::RemoveDeck => tr.decks_delete_deck(),
Op::RemoveNote => tr.studying_delete_note(),
Op::RenameDeck => tr.actions_rename_deck(),
Op::ScheduleAsNew => tr.actions_forget_card(),
Op::SetDueDate => tr.actions_set_due_date(),
Op::Suspend => tr.studying_suspend(),
Op::UnburyUnsuspend => tr.actions_unbury_unsuspend(),
Op::UpdateCard => tr.actions_update_card(),
Op::UpdateDeck => tr.actions_update_deck(),
Op::UpdateNote => tr.actions_update_note(),
Op::UpdatePreferences => tr.preferences_preferences(),
Op::UpdateTag => tr.actions_update_tag(),
Op::SetCardDeck => tr.browsing_change_deck(),
Op::SetFlag => tr.actions_set_flag(),
Op::FindAndReplace => tr.browsing_find_and_replace(),
Op::ClearUnusedTags => tr.browsing_clear_unused_tags(),
Op::SortCards => tr.browsing_reschedule(),
Op::RenameTag => tr.actions_rename_tag(),
Op::RemoveTag => tr.actions_remove_tag(),
Op::ReparentTag => tr.actions_rename_tag(),
Op::ReparentDeck => tr.actions_rename_deck(),
Op::BuildFilteredDeck => tr.actions_build_filtered_deck(),
Op::RebuildFilteredDeck => tr.actions_build_filtered_deck(),
Op::EmptyFilteredDeck => tr.studying_empty(),
Op::SetCurrentDeck => tr.browsing_change_deck(),
Op::UpdateDeckConfig => tr.deck_config_title(),
Op::AddNotetype => tr.actions_add_notetype(),
Op::RemoveNotetype => tr.actions_remove_notetype(),
Op::UpdateNotetype => tr.actions_update_notetype(),
Op::UpdateConfig => tr.actions_update_config(),
Op::Custom(name) => name.into(),
Op::ChangeNotetype => tr.browsing_change_notetype(),
Op::SkipUndo => return "".to_string(),
}
.into()
}
}
#[derive(Debug, PartialEq, Default, Clone, Copy)]
pub struct StateChanges {
pub card: bool,
pub note: bool,
pub deck: bool,
pub tag: bool,
pub notetype: bool,
pub config: bool,
pub deck_config: bool,
pub mtime: bool,
}
#[derive(Debug, PartialEq, Clone)]
pub struct OpChanges {
pub op: Op,
pub changes: StateChanges,
}
#[derive(Debug, PartialEq)]
pub struct OpOutput<T> {
pub output: T,
pub changes: OpChanges,
}
impl<T> OpOutput<T> {
pub(crate) fn map<F, N>(self, func: F) -> OpOutput<N>
where
F: FnOnce(T) -> N,
{
OpOutput {
output: func(self.output),
changes: self.changes,
}
}
}
impl OpChanges {
#[cfg(test)]
pub fn had_change(&self) -> bool {
let c = &self.changes;
c.card || c.config || c.deck || c.deck_config || c.note || c.notetype || c.tag || c.mtime
}
// These routines should return true even if the GUI may have
// special handling for an action, since we need to do the right
// thing when undoing, and if multiple windows of the same type are
// open.
pub fn requires_browser_table_redraw(&self) -> bool {
let c = &self.changes;
c.card || c.notetype || c.config || (c.note && self.op != Op::AddNote) || c.deck
}
pub fn requires_browser_sidebar_redraw(&self) -> bool {
let c = &self.changes;
c.tag || c.deck || c.notetype || c.config
}
pub fn requires_note_text_redraw(&self) -> bool {
let c = &self.changes;
c.note || c.notetype
}
pub fn requires_study_queue_rebuild(&self) -> bool {
let c = &self.changes;
(c.card && self.op != Op::SetFlag)
|| c.deck
|| (c.config && matches!(self.op, Op::SetCurrentDeck | Op::UpdatePreferences))
|| c.deck_config
}
}