From dc36a08f3ab6ea316eb0ef19bd0242acc7929564 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Thu, 31 Mar 2022 06:31:13 +0200 Subject: [PATCH] Also restore/keep position of new cards (#1760) * Also restore/keep position of new cards * Refactor Card::last_position() --- rslib/src/scheduler/new.rs | 70 ++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/rslib/src/scheduler/new.rs b/rslib/src/scheduler/new.rs index b40d06e8a..05a0d6999 100644 --- a/rslib/src/scheduler/new.rs +++ b/rslib/src/scheduler/new.rs @@ -18,9 +18,31 @@ use crate::{ }; impl Card { - fn schedule_as_new(&mut self, position: u32, reset_counts: bool) { + pub(crate) fn original_or_current_due(&self) -> i32 { + self.is_filtered() + .then(|| self.original_due) + .unwrap_or(self.due) + } + + pub(crate) fn last_position(&self) -> Option { + if self.ctype == CardType::New { + Some(self.original_or_current_due() as u32) + } else { + self.original_position + } + } + + /// True if the provided position has been used. + /// (Always true, if restore_position is false.) + pub(crate) fn schedule_as_new( + &mut self, + position: u32, + reset_counts: bool, + restore_position: bool, + ) -> bool { + let last_position = restore_position.then(|| self.last_position()).flatten(); self.remove_from_filtered_deck_before_reschedule(); - self.due = position as i32; + self.due = last_position.unwrap_or(position) as i32; self.ctype = CardType::New; self.queue = CardQueue::New; self.interval = 0; @@ -30,6 +52,8 @@ impl Card { self.reps = 0; self.lapses = 0; } + + last_position.is_none() } /// If the card is new, change its position, and return true. @@ -135,10 +159,7 @@ impl Collection { let cards = col.storage.all_searched_cards_in_search_order()?; for mut card in cards { let original = card.clone(); - if restore_position && card.original_position.is_some() { - card.schedule_as_new(card.original_position.unwrap(), reset_counts); - } else { - card.schedule_as_new(position, reset_counts); + if card.schedule_as_new(position, reset_counts, restore_position) { position += 1; } if log { @@ -301,6 +322,43 @@ mod test { } unreachable!("not random"); } + + #[test] + fn last_position() { + // new card + let mut card = Card::new(NoteId(0), 0, DeckId(1), 42); + assert_eq!(card.last_position(), Some(42)); + // in filtered deck + card.original_deck_id.0 = 1; + card.deck_id.0 = 2; + card.original_due = 42; + card.due = 123456789; + card.queue = CardQueue::Review; + assert_eq!(card.last_position(), Some(42)); + + // graduated card + let mut card = Card::new(NoteId(0), 0, DeckId(1), 42); + card.queue = CardQueue::Review; + card.ctype = CardType::Review; + card.due = 123456789; + // only recent clients remember the original position + assert_eq!(card.last_position(), None); + card.original_position = Some(42); + assert_eq!(card.last_position(), Some(42)); + } + + #[test] + fn scheduling_as_new() { + let mut card = Card::new(NoteId(0), 0, DeckId(1), 42); + card.reps = 4; + card.lapses = 2; + // keep counts and position + card.schedule_as_new(1, false, true); + assert_eq!((card.due, card.reps, card.lapses), (42, 4, 2)); + // complete reset + card.schedule_as_new(1, true, false); + assert_eq!((card.due, card.reps, card.lapses), (1, 0, 0)); + } } impl From for NewCardDueOrder {