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
|
# other types map directly to queues
|
||||||
_restoreQueueSnippet = f"""
|
_restoreQueueSnippet = f"""
|
||||||
queue = (case when type in ({CARD_TYPE_LRN},{CARD_TYPE_RELEARNING}) then
|
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
|
(case when (case when odue then odue else due end) > 1000000000 then
|
||||||
{QUEUE_TYPE_DAY_LEARN_RELEARN} end)
|
{QUEUE_TYPE_LRN} else {QUEUE_TYPE_DAY_LEARN_RELEARN} end)
|
||||||
else
|
else
|
||||||
type
|
type
|
||||||
end)
|
end)
|
||||||
|
@ -149,6 +149,23 @@ impl Card {
|
|||||||
self.ctype = CardType::New;
|
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)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct UpdateCardUndo(Card);
|
pub(crate) struct UpdateCardUndo(Card);
|
||||||
|
@ -49,6 +49,7 @@ pub(crate) enum ConfigKey {
|
|||||||
NewReviewMix,
|
NewReviewMix,
|
||||||
AnswerTimeLimitSecs,
|
AnswerTimeLimitSecs,
|
||||||
ShowDayLearningCardsFirst,
|
ShowDayLearningCardsFirst,
|
||||||
|
LastUnburiedDay,
|
||||||
}
|
}
|
||||||
#[derive(PartialEq, Serialize_repr, Deserialize_repr, Clone, Copy)]
|
#[derive(PartialEq, Serialize_repr, Deserialize_repr, Clone, Copy)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@ -76,6 +77,7 @@ impl From<ConfigKey> for &'static str {
|
|||||||
ConfigKey::NewReviewMix => "newSpread",
|
ConfigKey::NewReviewMix => "newSpread",
|
||||||
ConfigKey::AnswerTimeLimitSecs => "timeLim",
|
ConfigKey::AnswerTimeLimitSecs => "timeLim",
|
||||||
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
||||||
|
ConfigKey::LastUnburiedDay => "lastUnburied",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,6 +258,15 @@ impl Collection {
|
|||||||
pub(crate) fn set_day_learn_first(&self, on: bool) -> Result<()> {
|
pub(crate) fn set_day_learn_first(&self, on: bool) -> Result<()> {
|
||||||
self.set_config(ConfigKey::ShowDayLearningCardsFirst, &on)
|
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)]
|
#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
|
||||||
|
@ -78,4 +78,61 @@ impl Collection {
|
|||||||
SchedulerVersion::V2 => self.set_v2_rollover(hour as u32),
|
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))?
|
.query_and_then(NO_PARAMS, |r| row_to_card(r).map_err(Into::into))?
|
||||||
.collect()
|
.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)]
|
#[cfg(test)]
|
||||||
|
@ -319,6 +319,7 @@ where
|
|||||||
SyncActionRequired::FullSyncRequired { .. } => Ok(state.into()),
|
SyncActionRequired::FullSyncRequired { .. } => Ok(state.into()),
|
||||||
SyncActionRequired::NormalSyncRequired => {
|
SyncActionRequired::NormalSyncRequired => {
|
||||||
self.col.storage.begin_trx()?;
|
self.col.storage.begin_trx()?;
|
||||||
|
self.col.unbury_if_day_rolled_over()?;
|
||||||
match self.normal_sync_inner(state).await {
|
match self.normal_sync_inner(state).await {
|
||||||
Ok(success) => {
|
Ok(success) => {
|
||||||
self.col.storage.commit_trx()?;
|
self.col.storage.commit_trx()?;
|
||||||
|
Loading…
Reference in New Issue
Block a user