mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
move reschedCards() to backend
This commit is contained in:
parent
8f9037cf0f
commit
39212a38aa
8 changed files with 86 additions and 25 deletions
|
@ -105,6 +105,7 @@ service BackendService {
|
|||
rpc BuryOrSuspendCards (BuryOrSuspendCardsIn) returns (Empty);
|
||||
rpc EmptyFilteredDeck (DeckID) returns (Empty);
|
||||
rpc RebuildFilteredDeck (DeckID) returns (UInt32);
|
||||
rpc ScheduleCardsAsReviews (ScheduleCardsAsReviewsIn) returns (Empty);
|
||||
|
||||
// stats
|
||||
|
||||
|
@ -1056,3 +1057,9 @@ message BuryOrSuspendCardsIn {
|
|||
repeated int64 card_ids = 1;
|
||||
Mode mode = 2;
|
||||
}
|
||||
|
||||
message ScheduleCardsAsReviewsIn {
|
||||
repeated int64 card_ids = 1;
|
||||
uint32 min_interval = 2;
|
||||
uint32 max_interval = 3;
|
||||
}
|
||||
|
|
|
@ -1419,29 +1419,9 @@ and (queue={QUEUE_TYPE_NEW} or (queue={QUEUE_TYPE_REV} and due<=?))""",
|
|||
|
||||
def reschedCards(self, ids: List[int], imin: int, imax: int) -> None:
|
||||
"Put cards in review queue with a new interval in days (min, max)."
|
||||
d = []
|
||||
t = self.today
|
||||
mod = intTime()
|
||||
for id in ids:
|
||||
r = random.randint(imin, imax)
|
||||
d.append(
|
||||
(
|
||||
max(1, r),
|
||||
r + t,
|
||||
self.col.usn(),
|
||||
mod,
|
||||
STARTING_FACTOR,
|
||||
id,
|
||||
self.col.backend.schedule_cards_as_reviews(
|
||||
card_ids=ids, min_interval=imin, max_interval=imax
|
||||
)
|
||||
)
|
||||
self.remFromDyn(ids)
|
||||
self.col.db.executemany(
|
||||
f"""
|
||||
update cards set type={CARD_TYPE_REV},queue={QUEUE_TYPE_REV},ivl=?,due=?,odue=0,
|
||||
usn=?,mod=?,factor=? where id=?""",
|
||||
d,
|
||||
)
|
||||
self.col.log(ids)
|
||||
|
||||
def resetCards(self, ids: List[int]) -> None:
|
||||
"Completely reset cards for export."
|
||||
|
|
|
@ -547,6 +547,18 @@ impl BackendService for Backend {
|
|||
self.with_col(|col| col.rebuild_filtered_deck(input.did.into()).map(Into::into))
|
||||
}
|
||||
|
||||
fn schedule_cards_as_reviews(
|
||||
&mut self,
|
||||
input: pb::ScheduleCardsAsReviewsIn,
|
||||
) -> BackendResult<Empty> {
|
||||
let cids: Vec<_> = input.card_ids.into_iter().map(CardID).collect();
|
||||
let (min, max) = (input.min_interval, input.max_interval);
|
||||
self.with_col(|col| {
|
||||
col.reschedule_cards_as_reviews(&cids, min, max)
|
||||
.map(Into::into)
|
||||
})
|
||||
}
|
||||
|
||||
// statistics
|
||||
//-----------------------------------------------
|
||||
|
||||
|
|
|
@ -137,7 +137,18 @@ impl Card {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn remove_from_filtered_deck(&mut self, sched: SchedulerVersion) {
|
||||
/// Restores to the original deck and clears original_due.
|
||||
/// This does not update the queue or type, so should only be used as
|
||||
/// part of an operation that adjusts those separately.
|
||||
pub(crate) fn remove_from_filtered_deck_before_reschedule(&mut self) {
|
||||
if self.original_deck_id.0 != 0 {
|
||||
self.deck_id = self.original_deck_id;
|
||||
self.original_deck_id.0 = 0;
|
||||
self.original_due = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn remove_from_filtered_deck_restoring_queue(&mut self, sched: SchedulerVersion) {
|
||||
if self.original_deck_id.0 == 0 {
|
||||
// not in a filtered deck
|
||||
return;
|
||||
|
|
|
@ -66,7 +66,7 @@ impl Collection {
|
|||
for cid in cids {
|
||||
if let Some(mut card) = self.storage.get_card(*cid)? {
|
||||
let original = card.clone();
|
||||
card.remove_from_filtered_deck(sched);
|
||||
card.remove_from_filtered_deck_restoring_queue(sched);
|
||||
self.update_card(&mut card, &original, usn)?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ impl Collection {
|
|||
};
|
||||
if card.queue != desired_queue {
|
||||
if sched == SchedulerVersion::V1 {
|
||||
card.remove_from_filtered_deck(sched);
|
||||
card.remove_from_filtered_deck_restoring_queue(sched);
|
||||
card.remove_from_learning();
|
||||
}
|
||||
card.queue = desired_queue;
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
|||
pub mod bury_and_suspend;
|
||||
pub(crate) mod congrats;
|
||||
pub mod cutoff;
|
||||
mod reviews;
|
||||
pub mod timespan;
|
||||
|
||||
use chrono::FixedOffset;
|
||||
|
|
50
rslib/src/sched/reviews.rs
Normal file
50
rslib/src/sched/reviews.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::{
|
||||
card::{Card, CardID, CardQueue, CardType},
|
||||
collection::Collection,
|
||||
deckconf::INITIAL_EASE_FACTOR,
|
||||
err::Result,
|
||||
};
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
|
||||
impl Card {
|
||||
fn schedule_as_review(&mut self, interval: u32, today: u32) {
|
||||
self.remove_from_filtered_deck_before_reschedule();
|
||||
self.interval = interval.max(1);
|
||||
self.due = (today + interval) as i32;
|
||||
self.ctype = CardType::Review;
|
||||
self.queue = CardQueue::Review;
|
||||
if self.ease_factor == 0 {
|
||||
// unlike the old Python code, we leave the ease factor alone
|
||||
// if it's already set
|
||||
self.ease_factor = INITIAL_EASE_FACTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub fn reschedule_cards_as_reviews(
|
||||
&mut self,
|
||||
cids: &[CardID],
|
||||
min_days: u32,
|
||||
max_days: u32,
|
||||
) -> Result<()> {
|
||||
let usn = self.usn()?;
|
||||
let today = self.timing_today()?.days_elapsed;
|
||||
let mut rng = rand::thread_rng();
|
||||
let distribution = Uniform::from(min_days..=max_days);
|
||||
self.transact(None, |col| {
|
||||
col.set_search_table_to_card_ids(cids)?;
|
||||
for mut card in col.storage.all_searched_cards()? {
|
||||
let original = card.clone();
|
||||
let interval = distribution.sample(&mut rng);
|
||||
card.schedule_as_review(interval, today);
|
||||
col.update_card(&mut card, &original, usn)?;
|
||||
}
|
||||
col.clear_searched_cards()?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue