mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 15:32:23 -04:00
change failed card handling
The old delay1 behaviour isn't easy to achieve with the queue code, as we only refresh the queue when it's emptied, and if the user has delay1 set to say 9 hours, failed mature cards sitting in the queue could prevent subsequent young failures from being displayed. Instead we convert delay1 to a count in days in which to offset failed mature cards. 0 means the same time as delay0, 1 means show the card a day later, and so on. This means users will lose the ability to delay mature cards for x number of minutes more than young cards, but a scan of AnkiOnline decks indicates that's not often done. We also need to use a separate cutoff for failed cards, since we need to be able to display them as they expire if the user has disabled per-day scheduling. And instead of marking cards as due in the future, we set their due time to the current time, and move the delay0 calculation to getCardId(). This means that if the user changes their failed card settings from say 1 hour to 10 minutes, the changes apply to the currently failed cards and not just cards failed in the future.
This commit is contained in:
parent
b69fd48768
commit
7502fba5ce
1 changed files with 31 additions and 20 deletions
51
anki/deck.py
51
anki/deck.py
|
@ -98,7 +98,8 @@ decksTable = Table(
|
|||
Column('easyIntervalMax', Float, nullable=False, default=9.0),
|
||||
# delays on failure
|
||||
Column('delay0', Integer, nullable=False, default=600),
|
||||
Column('delay1', Integer, nullable=False, default=600),
|
||||
# days to delay mature fails
|
||||
Column('delay1', Integer, nullable=False, default=0),
|
||||
Column('delay2', Float, nullable=False, default=0.0),
|
||||
# collapsing future cards
|
||||
Column('collapseTime', Integer, nullable=False, default=1),
|
||||
|
@ -239,7 +240,7 @@ class Deck(object):
|
|||
self.cardLimit(
|
||||
"revActive", "revInactive",
|
||||
"select count(*) from cards c where type = 0 "
|
||||
"and combinedDue < :lim"), lim=self.dueCutoff)
|
||||
"and combinedDue < :lim"), lim=self.failedCutoff)
|
||||
|
||||
def _rebuildRevCount(self):
|
||||
self.revCount = self.s.scalar(
|
||||
|
@ -268,7 +269,7 @@ class Deck(object):
|
|||
"revActive", "revInactive", """
|
||||
select c.id, factId, combinedDue from cards c where
|
||||
type = 0 and combinedDue < :lim order by combinedDue
|
||||
limit %d""" % self.queueLimit), lim=self.dueCutoff)
|
||||
limit %d""" % self.queueLimit), lim=self.failedCutoff)
|
||||
self.failedQueue.reverse()
|
||||
|
||||
def _fillRevQueue(self):
|
||||
|
@ -380,18 +381,20 @@ when successive then 1 when reps then 0 else 2 end)
|
|||
return 2
|
||||
|
||||
def updateCutoff(self):
|
||||
d = datetime.datetime.utcfromtimestamp(
|
||||
time.time() - self.utcOffset) + datetime.timedelta(days=1)
|
||||
d = datetime.datetime(d.year, d.month, d.day)
|
||||
newday = self.utcOffset - time.timezone
|
||||
d += datetime.timedelta(seconds=newday)
|
||||
cutoff = time.mktime(d.timetuple())
|
||||
# cutoff must not be in the past
|
||||
while cutoff < time.time():
|
||||
cutoff += 86400
|
||||
# cutoff must not be more than 24 hours in the future
|
||||
cutoff = min(time.time() + 86400, cutoff)
|
||||
self.failedCutoff = cutoff
|
||||
if self.getBool("perDay"):
|
||||
d = datetime.datetime.utcfromtimestamp(
|
||||
time.time() - self.utcOffset) + datetime.timedelta(days=1)
|
||||
d = datetime.datetime(d.year, d.month, d.day)
|
||||
newday = self.utcOffset - time.timezone
|
||||
d += datetime.timedelta(seconds=newday)
|
||||
self.dueCutoff = time.mktime(d.timetuple())
|
||||
# cutoff must not be in the past
|
||||
while self.dueCutoff < time.time():
|
||||
self.dueCutoff += 86400
|
||||
# cutoff must not be more than 24 hours in the future
|
||||
self.dueCutoff = min(time.time() + 86400, self.dueCutoff)
|
||||
self.dueCutoff = cutoff
|
||||
else:
|
||||
self.dueCutoff = time.time()
|
||||
|
||||
|
@ -614,8 +617,9 @@ limit %s""" % (self.cramOrder, self.queueLimit)))
|
|||
self.updateNewCountToday()
|
||||
if self.failedQueue:
|
||||
# failed card due?
|
||||
if self.delay0 and self.failedQueue[-1][2] < time.time():
|
||||
return self.failedQueue[-1][0]
|
||||
if self.delay0:
|
||||
if self.failedQueue[-1][2] < time.time() + self.delay0:
|
||||
return self.failedQueue[-1][0]
|
||||
# failed card queue too big?
|
||||
if (self.failedCardMax and
|
||||
self.failedSoonCount >= self.failedCardMax):
|
||||
|
@ -941,9 +945,9 @@ where id != :id and factId = :factId""",
|
|||
"Return time when CARD will expire given EASE."
|
||||
if ease == 1:
|
||||
if oldState == "mature":
|
||||
due = self.delay1
|
||||
due = 0 + self.delay1*86400
|
||||
else:
|
||||
due = self.delay0
|
||||
due = 0
|
||||
else:
|
||||
due = card.interval * 86400.0
|
||||
return due + time.time()
|
||||
|
@ -2878,10 +2882,10 @@ where key = :key""", key=key, value=value):
|
|||
elif idx == 4:
|
||||
d = 259200
|
||||
self.delay0 = d
|
||||
self.delay1 = d
|
||||
self.delay1 = 0
|
||||
|
||||
def getFailedCardPolicy(self):
|
||||
if self.delay0 != self.delay1:
|
||||
if self.delay1:
|
||||
return 5
|
||||
d = self.delay0
|
||||
if self.collapseTime == 1:
|
||||
|
@ -3559,6 +3563,13 @@ update cards set type = type - 3 where type between 0 and 2 and priority = -3"""
|
|||
if deck.getBool("perDay"):
|
||||
deck.hardIntervalMin = max(1.0, deck.hardIntervalMin)
|
||||
deck.hardIntervalMax = max(1.1, deck.hardIntervalMax)
|
||||
# - new delay1 handling
|
||||
if deck.delay0 == deck.delay1:
|
||||
deck.delay1 = 0
|
||||
elif deck.delay1 >= 28800:
|
||||
deck.delay1 = 1
|
||||
else:
|
||||
deck.delay1 = 0
|
||||
# unsuspend buried/rev early - can remove priorities in the future
|
||||
ids = deck.s.column0(
|
||||
"select id from cards where type > 2 or priority between -2 and -1")
|
||||
|
|
Loading…
Reference in a new issue