'set due date' now undoable
This commit is contained in:
parent
ec8adf7371
commit
c1316bb65f
@ -21,7 +21,7 @@ import anki.template
|
||||
from anki import hooks
|
||||
from anki._backend import RustBackend
|
||||
from anki.cards import Card
|
||||
from anki.config import ConfigManager
|
||||
from anki.config import Config, ConfigManager
|
||||
from anki.consts import *
|
||||
from anki.dbproxy import DBProxy
|
||||
from anki.decks import DeckManager
|
||||
@ -49,7 +49,6 @@ from anki.utils import (
|
||||
SearchNode = _pb.SearchNode
|
||||
SearchJoiner = Literal["AND", "OR"]
|
||||
Progress = _pb.Progress
|
||||
Config = _pb.Config
|
||||
EmptyCardsReport = _pb.EmptyCardsReport
|
||||
GraphPreferences = _pb.GraphPreferences
|
||||
BuiltinSort = _pb.SortOrder.Builtin
|
||||
|
@ -24,9 +24,12 @@ from typing import Any
|
||||
from weakref import ref
|
||||
|
||||
import anki
|
||||
from anki._backend import backend_pb2 as _pb
|
||||
from anki.errors import NotFoundError
|
||||
from anki.utils import from_json_bytes, to_json_bytes
|
||||
|
||||
Config = _pb.Config
|
||||
|
||||
|
||||
class ConfigManager:
|
||||
def __init__(self, col: anki.collection.Collection):
|
||||
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
import anki
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki.config import Config
|
||||
|
||||
SchedTimingToday = _pb.SchedTimingTodayOut
|
||||
|
||||
@ -129,10 +130,20 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||
"Put cards at the end of the new queue."
|
||||
self.col._backend.schedule_cards_as_new(card_ids=card_ids, log=True)
|
||||
|
||||
def set_due_date(self, card_ids: List[int], days: str) -> None:
|
||||
def set_due_date(
|
||||
self,
|
||||
card_ids: List[int],
|
||||
days: str,
|
||||
config_key: Optional[Config.String.Key.V] = None,
|
||||
) -> None:
|
||||
"""Set cards to be due in `days`, turning them into review cards if necessary.
|
||||
`days` can be of the form '5' or '5..7'"""
|
||||
self.col._backend.set_due_date(card_ids=card_ids, days=days)
|
||||
`days` can be of the form '5' or '5..7'
|
||||
If `config_key` is provided, provided days will be remembered in config."""
|
||||
if config_key:
|
||||
key = Config.String(key=config_key)
|
||||
else:
|
||||
key = None
|
||||
self.col._backend.set_due_date(card_ids=card_ids, days=days, config_key=key)
|
||||
|
||||
def resetCards(self, ids: List[int]) -> None:
|
||||
"Completely reset cards for export."
|
||||
|
@ -1349,6 +1349,7 @@ where id in %s"""
|
||||
|
||||
def _after_schedule(self) -> None:
|
||||
self.model.reset()
|
||||
# updates undo status
|
||||
self.mw.requireReset(reason=ResetReason.BrowserReschedule, context=self)
|
||||
|
||||
@save_editor
|
||||
@ -1357,7 +1358,7 @@ where id in %s"""
|
||||
mw=self.mw,
|
||||
parent=self,
|
||||
card_ids=self.selectedCards(),
|
||||
default_key=Config.String.SET_DUE_BROWSER,
|
||||
config_key=Config.String.SET_DUE_BROWSER,
|
||||
on_done=self._after_schedule,
|
||||
)
|
||||
|
||||
|
@ -809,7 +809,7 @@ time = %(time)d;
|
||||
mw=self.mw,
|
||||
parent=self.mw,
|
||||
card_ids=[self.card.id],
|
||||
default_key=Config.String.SET_DUE_REVIEWER,
|
||||
config_key=Config.String.SET_DUE_REVIEWER,
|
||||
on_done=self.mw.reset,
|
||||
)
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from concurrent.futures import Future
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
import aqt
|
||||
from anki.collection import Config
|
||||
@ -18,20 +18,19 @@ def set_due_date_dialog(
|
||||
mw: aqt.AnkiQt,
|
||||
parent: QDialog,
|
||||
card_ids: List[int],
|
||||
default_key: Config.String.Key.V,
|
||||
config_key: Optional[Config.String.Key.V],
|
||||
on_done: Callable[[], None],
|
||||
) -> None:
|
||||
if not card_ids:
|
||||
return
|
||||
|
||||
default = mw.col.get_config_string(default_key)
|
||||
default = mw.col.get_config_string(config_key) if config_key else ""
|
||||
prompt = "\n".join(
|
||||
[
|
||||
tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT, cards=len(card_ids)),
|
||||
tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT_HINT),
|
||||
]
|
||||
)
|
||||
|
||||
(days, success) = getText(
|
||||
prompt=prompt,
|
||||
parent=parent,
|
||||
@ -42,9 +41,7 @@ def set_due_date_dialog(
|
||||
return
|
||||
|
||||
def set_due() -> None:
|
||||
mw.col.sched.set_due_date(card_ids, days)
|
||||
if days != default:
|
||||
mw.col.set_config_string(default_key, days)
|
||||
mw.col.sched.set_due_date(card_ids, days, config_key)
|
||||
|
||||
def after_set(fut: Future) -> None:
|
||||
try:
|
||||
|
@ -1273,6 +1273,7 @@ message ScheduleCardsAsNewIn {
|
||||
message SetDueDateIn {
|
||||
repeated int64 card_ids = 1;
|
||||
string days = 2;
|
||||
Config.String config_key = 3;
|
||||
}
|
||||
|
||||
message SortCardsIn {
|
||||
|
@ -43,6 +43,12 @@ impl From<StringKeyProto> for StringKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::config::String> for StringKey {
|
||||
fn from(key: pb::config::String) -> Self {
|
||||
key.key().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigService for Backend {
|
||||
fn get_config_json(&self, input: pb::String) -> Result<pb::Json> {
|
||||
self.with_col(|col| {
|
||||
|
@ -10,7 +10,6 @@ use crate::{
|
||||
prelude::*,
|
||||
scheduler::{
|
||||
new::NewCardSortOrder,
|
||||
parse_due_date_str,
|
||||
states::{CardState, NextCardStates},
|
||||
},
|
||||
stats::studied_today,
|
||||
@ -113,9 +112,10 @@ impl SchedulingService for Backend {
|
||||
}
|
||||
|
||||
fn set_due_date(&self, input: pb::SetDueDateIn) -> Result<pb::Empty> {
|
||||
let config = input.config_key.map(Into::into);
|
||||
let days = input.days;
|
||||
let cids: Vec<_> = input.card_ids.into_iter().map(CardID).collect();
|
||||
let spec = parse_due_date_str(&input.days)?;
|
||||
self.with_col(|col| col.set_due_date(&cids, spec).map(Into::into))
|
||||
self.with_col(|col| col.set_due_date(&cids, &days, config).map(Into::into))
|
||||
}
|
||||
|
||||
fn sort_cards(&self, input: pb::SortCardsIn) -> Result<pb::Empty> {
|
||||
|
@ -4,9 +4,11 @@
|
||||
use crate::{
|
||||
card::{Card, CardID, CardQueue, CardType},
|
||||
collection::Collection,
|
||||
config::StringKey,
|
||||
deckconf::INITIAL_EASE_FACTOR_THOUSANDS,
|
||||
err::Result,
|
||||
prelude::AnkiError,
|
||||
undo::UndoableOpKind,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
@ -84,12 +86,21 @@ pub fn parse_due_date_str(s: &str) -> Result<DueDateSpecifier> {
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub fn set_due_date(&mut self, cids: &[CardID], spec: DueDateSpecifier) -> Result<()> {
|
||||
/// `days` should be in a format parseable by `parse_due_date_str`.
|
||||
/// If `context` is provided, provided key will be updated with the new
|
||||
/// value of `days`.
|
||||
pub fn set_due_date(
|
||||
&mut self,
|
||||
cids: &[CardID],
|
||||
days: &str,
|
||||
context: Option<StringKey>,
|
||||
) -> Result<()> {
|
||||
let spec = parse_due_date_str(days)?;
|
||||
let usn = self.usn()?;
|
||||
let today = self.timing_today()?.days_elapsed;
|
||||
let mut rng = rand::thread_rng();
|
||||
let distribution = Uniform::from(spec.min..=spec.max);
|
||||
self.transact(None, |col| {
|
||||
self.transact(Some(UndoableOpKind::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();
|
||||
@ -99,6 +110,9 @@ impl Collection {
|
||||
col.update_card_inner(&mut card, &original, usn)?;
|
||||
}
|
||||
col.storage.clear_searched_cards_table()?;
|
||||
if let Some(key) = context {
|
||||
col.set_string(key, days)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ pub enum UndoableOpKind {
|
||||
RemoveDeck,
|
||||
RemoveNote,
|
||||
RenameDeck,
|
||||
SetDueDate,
|
||||
Suspend,
|
||||
UnburyUnsuspend,
|
||||
UpdateCard,
|
||||
@ -37,6 +38,7 @@ impl Collection {
|
||||
UndoableOpKind::RemoveDeck => TR::DecksDeleteDeck,
|
||||
UndoableOpKind::RemoveNote => TR::StudyingDeleteNote,
|
||||
UndoableOpKind::RenameDeck => TR::ActionsRenameDeck,
|
||||
UndoableOpKind::SetDueDate => TR::ActionsSetDueDate,
|
||||
UndoableOpKind::Suspend => TR::StudyingSuspend,
|
||||
UndoableOpKind::UnburyUnsuspend => TR::UndoUnburyUnsuspend,
|
||||
UndoableOpKind::UpdateCard => TR::UndoUpdateCard,
|
||||
|
Loading…
Reference in New Issue
Block a user