check if we need to unbury at the start of the sync process
https://forums.ankiweb.net/t/bug-buried-cards-in-filtered-decks-not-being-unburied-next-day/2541/24
This commit is contained in:
parent
3bd85bf180
commit
4662a9fe1a
@ -1456,8 +1456,8 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||
# other types map directly to queues
|
||||
_restoreQueueSnippet = f"""
|
||||
queue = (case when type in ({CARD_TYPE_LRN},{CARD_TYPE_RELEARNING}) then
|
||||
(case when (case when odue then odue else due end) > 1000000000 then 1 else
|
||||
{QUEUE_TYPE_DAY_LEARN_RELEARN} end)
|
||||
(case when (case when odue then odue else due end) > 1000000000 then
|
||||
{QUEUE_TYPE_LRN} else {QUEUE_TYPE_DAY_LEARN_RELEARN} end)
|
||||
else
|
||||
type
|
||||
end)
|
||||
|
@ -149,6 +149,23 @@ impl Card {
|
||||
self.ctype = CardType::New;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn restore_queue_after_bury_or_suspend(&mut self) {
|
||||
self.queue = match self.ctype {
|
||||
CardType::Learn | CardType::Relearn => {
|
||||
let original_due = if self.odue > 0 { self.odue } else { self.due };
|
||||
if original_due > 1_000_000_000 {
|
||||
// previous interval was in seconds
|
||||
CardQueue::Learn
|
||||
} else {
|
||||
// previous interval was in days
|
||||
CardQueue::DayLearn
|
||||
}
|
||||
}
|
||||
CardType::New => CardQueue::New,
|
||||
CardType::Review => CardQueue::Review,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UpdateCardUndo(Card);
|
||||
|
@ -49,6 +49,7 @@ pub(crate) enum ConfigKey {
|
||||
NewReviewMix,
|
||||
AnswerTimeLimitSecs,
|
||||
ShowDayLearningCardsFirst,
|
||||
LastUnburiedDay,
|
||||
}
|
||||
#[derive(PartialEq, Serialize_repr, Deserialize_repr, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
@ -76,6 +77,7 @@ impl From<ConfigKey> for &'static str {
|
||||
ConfigKey::NewReviewMix => "newSpread",
|
||||
ConfigKey::AnswerTimeLimitSecs => "timeLim",
|
||||
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
||||
ConfigKey::LastUnburiedDay => "lastUnburied",
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -256,6 +258,15 @@ impl Collection {
|
||||
pub(crate) fn set_day_learn_first(&self, on: bool) -> Result<()> {
|
||||
self.set_config(ConfigKey::ShowDayLearningCardsFirst, &on)
|
||||
}
|
||||
|
||||
pub(crate) fn get_last_unburied_day(&self) -> u32 {
|
||||
self.get_config_optional(ConfigKey::LastUnburiedDay)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(crate) fn set_last_unburied_day(&self, day: u32) -> Result<()> {
|
||||
self.set_config(ConfigKey::LastUnburiedDay, &day)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
|
||||
|
@ -78,4 +78,61 @@ impl Collection {
|
||||
SchedulerVersion::V2 => self.set_v2_rollover(hour as u32),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unbury_if_day_rolled_over(&mut self) -> Result<()> {
|
||||
let last_unburied = self.get_last_unburied_day();
|
||||
let today = self.timing_today()?.days_elapsed;
|
||||
if last_unburied < today || (today + 7) < last_unburied {
|
||||
self.unbury_on_day_rollover()?;
|
||||
self.set_last_unburied_day(today)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unbury_on_day_rollover(&mut self) -> Result<()> {
|
||||
self.search_cards_into_table("is:buried")?;
|
||||
self.storage.for_each_card_in_search(|mut card| {
|
||||
card.restore_queue_after_bury_or_suspend();
|
||||
self.storage.update_card(&card)
|
||||
})?;
|
||||
self.clear_searched_cards()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
card::{Card, CardQueue},
|
||||
collection::{open_test_collection, Collection},
|
||||
search::SortMode,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn unbury() {
|
||||
let mut col = open_test_collection();
|
||||
let mut card = Card::default();
|
||||
card.queue = CardQueue::UserBuried;
|
||||
col.add_card(&mut card).unwrap();
|
||||
let assert_count = |col: &mut Collection, cnt| {
|
||||
assert_eq!(
|
||||
col.search_cards("is:buried", SortMode::NoOrder)
|
||||
.unwrap()
|
||||
.len(),
|
||||
cnt
|
||||
);
|
||||
};
|
||||
assert_count(&mut col, 1);
|
||||
// day 0, last unburied 0, so no change
|
||||
col.unbury_if_day_rolled_over().unwrap();
|
||||
assert_count(&mut col, 1);
|
||||
// move creation time back and it should succeed
|
||||
let mut stamp = col.storage.creation_stamp().unwrap();
|
||||
stamp.0 -= 86_400;
|
||||
col.storage.set_creation_stamp(stamp).unwrap();
|
||||
col.unbury_if_day_rolled_over().unwrap();
|
||||
assert_count(&mut col, 0);
|
||||
}
|
||||
}
|
||||
|
@ -260,6 +260,23 @@ impl super::SqliteStorage {
|
||||
.query_and_then(NO_PARAMS, |r| row_to_card(r).map_err(Into::into))?
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn for_each_card_in_search<F>(&self, mut func: F) -> Result<()>
|
||||
where
|
||||
F: FnMut(Card) -> Result<()>,
|
||||
{
|
||||
let mut stmt = self.db.prepare_cached(concat!(
|
||||
include_str!("get_card.sql"),
|
||||
" where id in (select id from search_cids)"
|
||||
))?;
|
||||
let mut rows = stmt.query(NO_PARAMS)?;
|
||||
while let Some(row) = rows.next()? {
|
||||
let card = row_to_card(row)?;
|
||||
func(card)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -319,6 +319,7 @@ where
|
||||
SyncActionRequired::FullSyncRequired { .. } => Ok(state.into()),
|
||||
SyncActionRequired::NormalSyncRequired => {
|
||||
self.col.storage.begin_trx()?;
|
||||
self.col.unbury_if_day_rolled_over()?;
|
||||
match self.normal_sync_inner(state).await {
|
||||
Ok(success) => {
|
||||
self.col.storage.commit_trx()?;
|
||||
|
Loading…
Reference in New Issue
Block a user