mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
commit
f7ebb8c28f
17 changed files with 557 additions and 461 deletions
|
@ -48,8 +48,8 @@ class Card:
|
||||||
self.id = timestampID(col.db, "cards")
|
self.id = timestampID(col.db, "cards")
|
||||||
self.did = 1
|
self.did = 1
|
||||||
self.crt = intTime()
|
self.crt = intTime()
|
||||||
self.type = 0
|
self.type = CARD_TYPE_NEW
|
||||||
self.queue = 0
|
self.queue = QUEUE_TYPE_NEW
|
||||||
self.ivl = 0
|
self.ivl = 0
|
||||||
self.factor = 0
|
self.factor = 0
|
||||||
self.reps = 0
|
self.reps = 0
|
||||||
|
@ -88,7 +88,11 @@ class Card:
|
||||||
self.mod = intTime()
|
self.mod = intTime()
|
||||||
self.usn = self.col.usn()
|
self.usn = self.col.usn()
|
||||||
# bug check
|
# bug check
|
||||||
if self.queue == 2 and self.odue and not self.col.decks.isDyn(self.did):
|
if (
|
||||||
|
self.queue == QUEUE_TYPE_REV
|
||||||
|
and self.odue
|
||||||
|
and not self.col.decks.isDyn(self.did)
|
||||||
|
):
|
||||||
hooks.card_odue_was_invalid()
|
hooks.card_odue_was_invalid()
|
||||||
assert self.due < 4294967296
|
assert self.due < 4294967296
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
|
@ -120,7 +124,11 @@ insert or replace into cards values
|
||||||
self.mod = intTime()
|
self.mod = intTime()
|
||||||
self.usn = self.col.usn()
|
self.usn = self.col.usn()
|
||||||
# bug checks
|
# bug checks
|
||||||
if self.queue == 2 and self.odue and not self.col.decks.isDyn(self.did):
|
if (
|
||||||
|
self.queue == QUEUE_TYPE_REV
|
||||||
|
and self.odue
|
||||||
|
and not self.col.decks.isDyn(self.did)
|
||||||
|
):
|
||||||
hooks.card_odue_was_invalid()
|
hooks.card_odue_was_invalid()
|
||||||
assert self.due < 4294967296
|
assert self.due < 4294967296
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
|
|
|
@ -14,6 +14,22 @@ NEW_CARDS_FIRST = 2
|
||||||
NEW_CARDS_RANDOM = 0
|
NEW_CARDS_RANDOM = 0
|
||||||
NEW_CARDS_DUE = 1
|
NEW_CARDS_DUE = 1
|
||||||
|
|
||||||
|
# Queue types
|
||||||
|
QUEUE_TYPE_MANUALLY_BURIED = -3
|
||||||
|
QUEUE_TYPE_SIBLING_BURIED = -2
|
||||||
|
QUEUE_TYPE_SUSPENDED = -1
|
||||||
|
QUEUE_TYPE_NEW = 0
|
||||||
|
QUEUE_TYPE_LRN = 1
|
||||||
|
QUEUE_TYPE_REV = 2
|
||||||
|
QUEUE_TYPE_DAY_LEARN_RELEARN = 3
|
||||||
|
QUEUE_TYPE_PREVIEW = 4
|
||||||
|
|
||||||
|
# Card types
|
||||||
|
CARD_TYPE_NEW = 0
|
||||||
|
CARD_TYPE_LRN = 1
|
||||||
|
CARD_TYPE_REV = 2
|
||||||
|
CARD_TYPE_RELEARNING = 3
|
||||||
|
|
||||||
# removal types
|
# removal types
|
||||||
REM_CARD = 0
|
REM_CARD = 0
|
||||||
REM_NOTE = 1
|
REM_NOTE = 1
|
||||||
|
@ -27,6 +43,10 @@ COUNT_REMAINING = 1
|
||||||
MEDIA_ADD = 0
|
MEDIA_ADD = 0
|
||||||
MEDIA_REM = 1
|
MEDIA_REM = 1
|
||||||
|
|
||||||
|
# Kind of decks
|
||||||
|
DECK_STD = 0
|
||||||
|
DECK_DYN = 1
|
||||||
|
|
||||||
# dynamic deck order
|
# dynamic deck order
|
||||||
DYN_OLDEST = 0
|
DYN_OLDEST = 0
|
||||||
DYN_RANDOM = 1
|
DYN_RANDOM = 1
|
||||||
|
@ -55,6 +75,22 @@ SYNC_VER = 9
|
||||||
|
|
||||||
HELP_SITE = "http://ankisrs.net/docs/manual.html"
|
HELP_SITE = "http://ankisrs.net/docs/manual.html"
|
||||||
|
|
||||||
|
# Leech actions
|
||||||
|
LEECH_SUSPEND = 0
|
||||||
|
LEECH_TAGONLY = 1
|
||||||
|
|
||||||
|
# Buttons
|
||||||
|
BUTTON_ONE = 1
|
||||||
|
BUTTON_TWO = 2
|
||||||
|
BUTTON_THREE = 3
|
||||||
|
BUTTON_FOUR = 4
|
||||||
|
|
||||||
|
# Revlog types
|
||||||
|
REVLOG_LRN = 0
|
||||||
|
REVLOG_REV = 1
|
||||||
|
REVLOG_RELRN = 2
|
||||||
|
REVLOG_CRAM = 3
|
||||||
|
|
||||||
# Labels
|
# Labels
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ defaultDeck = {
|
||||||
"conf": 1,
|
"conf": 1,
|
||||||
"usn": 0,
|
"usn": 0,
|
||||||
"desc": "",
|
"desc": "",
|
||||||
"dyn": 0, # anki uses int/bool interchangably here
|
"dyn": DECK_STD, # anki uses int/bool interchangably here
|
||||||
"collapsed": False,
|
"collapsed": False,
|
||||||
# added in beta11
|
# added in beta11
|
||||||
"extendNew": 10,
|
"extendNew": 10,
|
||||||
|
@ -40,7 +40,7 @@ defaultDynamicDeck = {
|
||||||
"lrnToday": [0, 0],
|
"lrnToday": [0, 0],
|
||||||
"timeToday": [0, 0],
|
"timeToday": [0, 0],
|
||||||
"collapsed": False,
|
"collapsed": False,
|
||||||
"dyn": 1,
|
"dyn": DECK_DYN,
|
||||||
"desc": "",
|
"desc": "",
|
||||||
"usn": 0,
|
"usn": 0,
|
||||||
"delays": None,
|
"delays": None,
|
||||||
|
@ -71,7 +71,7 @@ defaultConf = {
|
||||||
"minInt": 1,
|
"minInt": 1,
|
||||||
"leechFails": 8,
|
"leechFails": 8,
|
||||||
# type 0=suspend, 1=tagonly
|
# type 0=suspend, 1=tagonly
|
||||||
"leechAction": 0,
|
"leechAction": LEECH_SUSPEND,
|
||||||
},
|
},
|
||||||
"rev": {
|
"rev": {
|
||||||
"perDay": 200,
|
"perDay": 200,
|
||||||
|
|
|
@ -240,7 +240,7 @@ select distinct(n.id) from cards c, notes n where c.nid=n.id and """
|
||||||
elif type == "cardDue":
|
elif type == "cardDue":
|
||||||
sort = "c.type, c.due"
|
sort = "c.type, c.due"
|
||||||
elif type == "cardEase":
|
elif type == "cardEase":
|
||||||
sort = "c.type == 0, c.factor"
|
sort = f"c.type == {CARD_TYPE_NEW}, c.factor"
|
||||||
elif type == "cardLapses":
|
elif type == "cardLapses":
|
||||||
sort = "c.lapses"
|
sort = "c.lapses"
|
||||||
elif type == "cardIvl":
|
elif type == "cardIvl":
|
||||||
|
@ -271,18 +271,18 @@ select distinct(n.id) from cards c, notes n where c.nid=n.id and """
|
||||||
if val == "review":
|
if val == "review":
|
||||||
n = 2
|
n = 2
|
||||||
elif val == "new":
|
elif val == "new":
|
||||||
n = 0
|
n = CARD_TYPE_NEW
|
||||||
else:
|
else:
|
||||||
return "queue in (1, 3)"
|
return f"queue in ({QUEUE_TYPE_LRN}, {QUEUE_TYPE_DAY_LEARN_RELEARN})"
|
||||||
return "type = %d" % n
|
return "type = %d" % n
|
||||||
elif val == "suspended":
|
elif val == "suspended":
|
||||||
return "c.queue = -1"
|
return "c.queue = -1"
|
||||||
elif val == "buried":
|
elif val == "buried":
|
||||||
return "c.queue in (-2, -3)"
|
return f"c.queue in ({QUEUE_TYPE_SIBLING_BURIED}, {QUEUE_TYPE_MANUALLY_BURIED})"
|
||||||
elif val == "due":
|
elif val == "due":
|
||||||
return """
|
return f"""
|
||||||
(c.queue in (2,3) and c.due <= %d) or
|
(c.queue in ({QUEUE_TYPE_REV},{QUEUE_TYPE_DAY_LEARN_RELEARN}) and c.due <= %d) or
|
||||||
(c.queue = 1 and c.due <= %d)""" % (
|
(c.queue = {QUEUE_TYPE_LRN} and c.due <= %d)""" % (
|
||||||
self.col.sched.today,
|
self.col.sched.today,
|
||||||
self.col.sched.dayCutoff,
|
self.col.sched.dayCutoff,
|
||||||
)
|
)
|
||||||
|
@ -349,7 +349,7 @@ select distinct(n.id) from cards c, notes n where c.nid=n.id and """
|
||||||
if prop == "due":
|
if prop == "due":
|
||||||
val += self.col.sched.today
|
val += self.col.sched.today
|
||||||
# only valid for review/daily learning
|
# only valid for review/daily learning
|
||||||
q.append("(c.queue in (2,3))")
|
q.append(f"(c.queue in ({QUEUE_TYPE_REV},{QUEUE_TYPE_DAY_LEARN_RELEARN}))")
|
||||||
elif prop == "ease":
|
elif prop == "ease":
|
||||||
prop = "factor"
|
prop = "factor"
|
||||||
val = int(val * 1000)
|
val = int(val * 1000)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import unicodedata
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from anki.collection import _Collection
|
from anki.collection import _Collection
|
||||||
|
from anki.consts import *
|
||||||
from anki.importing.base import Importer
|
from anki.importing.base import Importer
|
||||||
from anki.lang import _
|
from anki.lang import _
|
||||||
from anki.storage import Collection
|
from anki.storage import Collection
|
||||||
|
@ -343,7 +344,10 @@ class Anki2Importer(Importer):
|
||||||
card[4] = intTime()
|
card[4] = intTime()
|
||||||
card[5] = usn
|
card[5] = usn
|
||||||
# review cards have a due date relative to collection
|
# review cards have a due date relative to collection
|
||||||
if card[7] in (2, 3) or card[6] == 2:
|
if (
|
||||||
|
card[7] in (QUEUE_TYPE_REV, QUEUE_TYPE_DAY_LEARN_RELEARN)
|
||||||
|
or card[6] == CARD_TYPE_REV
|
||||||
|
):
|
||||||
card[8] -= aheadBy
|
card[8] -= aheadBy
|
||||||
# odue needs updating too
|
# odue needs updating too
|
||||||
if card[14]:
|
if card[14]:
|
||||||
|
@ -356,13 +360,13 @@ class Anki2Importer(Importer):
|
||||||
card[8] = card[14]
|
card[8] = card[14]
|
||||||
card[14] = 0
|
card[14] = 0
|
||||||
# queue
|
# queue
|
||||||
if card[6] == 1: # type
|
if card[6] == CARD_TYPE_LRN: # type
|
||||||
card[7] = 0
|
card[7] = QUEUE_TYPE_NEW
|
||||||
else:
|
else:
|
||||||
card[7] = card[6]
|
card[7] = card[6]
|
||||||
# type
|
# type
|
||||||
if card[6] == 1:
|
if card[6] == CARD_TYPE_LRN:
|
||||||
card[6] = 0
|
card[6] = CARD_TYPE_NEW
|
||||||
cards.append(card)
|
cards.append(card)
|
||||||
# we need to import revlog, rewriting card ids and bumping usn
|
# we need to import revlog, rewriting card ids and bumping usn
|
||||||
for rev in self.src.db.execute("select * from revlog where cid = ?", scid):
|
for rev in self.src.db.execute("select * from revlog where cid = ?", scid):
|
||||||
|
|
|
@ -52,9 +52,12 @@ class ForeignCard:
|
||||||
# If the first field of the model is not in the map, the map is invalid.
|
# If the first field of the model is not in the map, the map is invalid.
|
||||||
|
|
||||||
# The import mode is one of:
|
# The import mode is one of:
|
||||||
# 0: update if first field matches existing note
|
# UPDATE_MODE: update if first field matches existing note
|
||||||
# 1: ignore if first field matches existing note
|
# IGNORE_MODE: ignore if first field matches existing note
|
||||||
# 2: import even if first field matches existing note
|
# ADD_MODE: import even if first field matches existing note
|
||||||
|
UPDATE_MODE = 0
|
||||||
|
IGNORE_MODE = 1
|
||||||
|
ADD_MODE = 2
|
||||||
|
|
||||||
|
|
||||||
class NoteImporter(Importer):
|
class NoteImporter(Importer):
|
||||||
|
@ -62,7 +65,7 @@ class NoteImporter(Importer):
|
||||||
needMapper = True
|
needMapper = True
|
||||||
needDelimiter = False
|
needDelimiter = False
|
||||||
allowHTML = False
|
allowHTML = False
|
||||||
importMode = 0
|
importMode = UPDATE_MODE
|
||||||
mapping: Optional[List[str]]
|
mapping: Optional[List[str]]
|
||||||
tagModified: Optional[str]
|
tagModified: Optional[str]
|
||||||
|
|
||||||
|
@ -153,7 +156,7 @@ class NoteImporter(Importer):
|
||||||
self.log.append(_("Empty first field: %s") % " ".join(n.fields))
|
self.log.append(_("Empty first field: %s") % " ".join(n.fields))
|
||||||
continue
|
continue
|
||||||
# earlier in import?
|
# earlier in import?
|
||||||
if fld0 in firsts and self.importMode != 2:
|
if fld0 in firsts and self.importMode != ADD_MODE:
|
||||||
# duplicates in source file; log and ignore
|
# duplicates in source file; log and ignore
|
||||||
self.log.append(_("Appeared twice in file: %s") % fld0)
|
self.log.append(_("Appeared twice in file: %s") % fld0)
|
||||||
continue
|
continue
|
||||||
|
@ -168,16 +171,16 @@ class NoteImporter(Importer):
|
||||||
if fld0 == sflds[0]:
|
if fld0 == sflds[0]:
|
||||||
# duplicate
|
# duplicate
|
||||||
found = True
|
found = True
|
||||||
if self.importMode == 0:
|
if self.importMode == UPDATE_MODE:
|
||||||
data = self.updateData(n, id, sflds)
|
data = self.updateData(n, id, sflds)
|
||||||
if data:
|
if data:
|
||||||
updates.append(data)
|
updates.append(data)
|
||||||
updateLog.append(updateLogTxt % fld0)
|
updateLog.append(updateLogTxt % fld0)
|
||||||
dupeCount += 1
|
dupeCount += 1
|
||||||
found = True
|
found = True
|
||||||
elif self.importMode == 1:
|
elif self.importMode == IGNORE_MODE:
|
||||||
dupeCount += 1
|
dupeCount += 1
|
||||||
elif self.importMode == 2:
|
elif self.importMode == ADD_MODE:
|
||||||
# allow duplicates in this case
|
# allow duplicates in this case
|
||||||
if fld0 not in dupes:
|
if fld0 not in dupes:
|
||||||
# only show message once, no matter how many
|
# only show message once, no matter how many
|
||||||
|
@ -214,9 +217,9 @@ class NoteImporter(Importer):
|
||||||
ngettext("%d note updated", "%d notes updated", self.updateCount)
|
ngettext("%d note updated", "%d notes updated", self.updateCount)
|
||||||
% self.updateCount
|
% self.updateCount
|
||||||
)
|
)
|
||||||
if self.importMode == 0:
|
if self.importMode == UPDATE_MODE:
|
||||||
unchanged = dupeCount - self.updateCount
|
unchanged = dupeCount - self.updateCount
|
||||||
elif self.importMode == 1:
|
elif self.importMode == IGNORE_MODE:
|
||||||
unchanged = dupeCount
|
unchanged = dupeCount
|
||||||
else:
|
else:
|
||||||
unchanged = 0
|
unchanged = 0
|
||||||
|
|
|
@ -67,28 +67,28 @@ class Scheduler:
|
||||||
self._burySiblings(card)
|
self._burySiblings(card)
|
||||||
card.reps += 1
|
card.reps += 1
|
||||||
# former is for logging new cards, latter also covers filt. decks
|
# former is for logging new cards, latter also covers filt. decks
|
||||||
card.wasNew = card.type == 0
|
card.wasNew = card.type == CARD_TYPE_NEW
|
||||||
wasNewQ = card.queue == 0
|
wasNewQ = card.queue == QUEUE_TYPE_NEW
|
||||||
if wasNewQ:
|
if wasNewQ:
|
||||||
# came from the new queue, move to learning
|
# came from the new queue, move to learning
|
||||||
card.queue = 1
|
card.queue = QUEUE_TYPE_LRN
|
||||||
# if it was a new card, it's now a learning card
|
# if it was a new card, it's now a learning card
|
||||||
if card.type == 0:
|
if card.type == CARD_TYPE_NEW:
|
||||||
card.type = 1
|
card.type = CARD_TYPE_LRN
|
||||||
# init reps to graduation
|
# init reps to graduation
|
||||||
card.left = self._startingLeft(card)
|
card.left = self._startingLeft(card)
|
||||||
# dynamic?
|
# dynamic?
|
||||||
if card.odid and card.type == 2:
|
if card.odid and card.type == CARD_TYPE_REV:
|
||||||
if self._resched(card):
|
if self._resched(card):
|
||||||
# reviews get their ivl boosted on first sight
|
# reviews get their ivl boosted on first sight
|
||||||
card.ivl = self._dynIvlBoost(card)
|
card.ivl = self._dynIvlBoost(card)
|
||||||
card.odue = self.today + card.ivl
|
card.odue = self.today + card.ivl
|
||||||
self._updateStats(card, "new")
|
self._updateStats(card, "new")
|
||||||
if card.queue in (1, 3):
|
if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
||||||
self._answerLrnCard(card, ease)
|
self._answerLrnCard(card, ease)
|
||||||
if not wasNewQ:
|
if not wasNewQ:
|
||||||
self._updateStats(card, "lrn")
|
self._updateStats(card, "lrn")
|
||||||
elif card.queue == 2:
|
elif card.queue == QUEUE_TYPE_REV:
|
||||||
self._answerRevCard(card, ease)
|
self._answerRevCard(card, ease)
|
||||||
self._updateStats(card, "rev")
|
self._updateStats(card, "rev")
|
||||||
else:
|
else:
|
||||||
|
@ -112,9 +112,9 @@ class Scheduler:
|
||||||
"Return counts over next DAYS. Includes today."
|
"Return counts over next DAYS. Includes today."
|
||||||
daysd = dict(
|
daysd = dict(
|
||||||
self.col.db.all(
|
self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select due, count() from cards
|
select due, count() from cards
|
||||||
where did in %s and queue = 2
|
where did in %s and queue = {QUEUE_TYPE_REV}
|
||||||
and due between ? and ?
|
and due between ? and ?
|
||||||
group by due
|
group by due
|
||||||
order by due"""
|
order by due"""
|
||||||
|
@ -132,20 +132,20 @@ order by due"""
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def countIdx(self, card):
|
def countIdx(self, card):
|
||||||
if card.queue == 3:
|
if card.queue == QUEUE_TYPE_DAY_LEARN_RELEARN:
|
||||||
return 1
|
return 1
|
||||||
return card.queue
|
return card.queue
|
||||||
|
|
||||||
def answerButtons(self, card):
|
def answerButtons(self, card):
|
||||||
if card.odue:
|
if card.odue:
|
||||||
# normal review in dyn deck?
|
# normal review in dyn deck?
|
||||||
if card.odid and card.queue == 2:
|
if card.odid and card.queue == QUEUE_TYPE_REV:
|
||||||
return 4
|
return 4
|
||||||
conf = self._lrnConf(card)
|
conf = self._lrnConf(card)
|
||||||
if card.type in (0, 1) or len(conf["delays"]) > 1:
|
if card.type in (CARD_TYPE_NEW, CARD_TYPE_LRN) or len(conf["delays"]) > 1:
|
||||||
return 3
|
return 3
|
||||||
return 2
|
return 2
|
||||||
elif card.queue == 2:
|
elif card.queue == QUEUE_TYPE_REV:
|
||||||
return 4
|
return 4
|
||||||
else:
|
else:
|
||||||
return 3
|
return 3
|
||||||
|
@ -153,18 +153,25 @@ order by due"""
|
||||||
def unburyCards(self):
|
def unburyCards(self):
|
||||||
"Unbury cards."
|
"Unbury cards."
|
||||||
self.col.conf["lastUnburied"] = self.today
|
self.col.conf["lastUnburied"] = self.today
|
||||||
self.col.log(self.col.db.list("select id from cards where queue = -2"))
|
self.col.log(
|
||||||
self.col.db.execute("update cards set queue=type where queue = -2")
|
self.col.db.list(
|
||||||
|
f"select id from cards where queue = {QUEUE_TYPE_SIBLING_BURIED}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.col.db.execute(
|
||||||
|
f"update cards set queue=type where queue = {QUEUE_TYPE_SIBLING_BURIED}"
|
||||||
|
)
|
||||||
|
|
||||||
def unburyCardsForDeck(self):
|
def unburyCardsForDeck(self):
|
||||||
sids = ids2str(self.col.decks.active())
|
sids = ids2str(self.col.decks.active())
|
||||||
self.col.log(
|
self.col.log(
|
||||||
self.col.db.list(
|
self.col.db.list(
|
||||||
"select id from cards where queue = -2 and did in %s" % sids
|
f"select id from cards where queue = {QUEUE_TYPE_SIBLING_BURIED} and did in %s"
|
||||||
|
% sids
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set mod=?,usn=?,queue=type where queue = -2 and did in %s"
|
f"update cards set mod=?,usn=?,queue=type where queue = {QUEUE_TYPE_SIBLING_BURIED} and did in %s"
|
||||||
% sids,
|
% sids,
|
||||||
intTime(),
|
intTime(),
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
|
@ -348,9 +355,9 @@ order by due"""
|
||||||
|
|
||||||
def _resetNewCount(self):
|
def _resetNewCount(self):
|
||||||
cntFn = lambda did, lim: self.col.db.scalar(
|
cntFn = lambda did, lim: self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from (select 1 from cards where
|
select count() from (select 1 from cards where
|
||||||
did = ? and queue = 0 limit ?)""",
|
did = ? and queue = {QUEUE_TYPE_NEW} limit ?)""",
|
||||||
did,
|
did,
|
||||||
lim,
|
lim,
|
||||||
)
|
)
|
||||||
|
@ -373,8 +380,8 @@ did = ? and queue = 0 limit ?)""",
|
||||||
if lim:
|
if lim:
|
||||||
# fill the queue with the current did
|
# fill the queue with the current did
|
||||||
self._newQueue = self.col.db.list(
|
self._newQueue = self.col.db.list(
|
||||||
"""
|
f"""
|
||||||
select id from cards where did = ? and queue = 0 order by due,ord limit ?""",
|
select id from cards where did = ? and queue = {QUEUE_TYPE_NEW} order by due,ord limit ?""",
|
||||||
did,
|
did,
|
||||||
lim,
|
lim,
|
||||||
)
|
)
|
||||||
|
@ -436,9 +443,9 @@ did = ? and queue = 0 limit ?)""",
|
||||||
return 0
|
return 0
|
||||||
lim = min(lim, self.reportLimit)
|
lim = min(lim, self.reportLimit)
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from
|
select count() from
|
||||||
(select 1 from cards where did = ? and queue = 0 limit ?)""",
|
(select 1 from cards where did = ? and queue = {QUEUE_TYPE_NEW} limit ?)""",
|
||||||
did,
|
did,
|
||||||
lim,
|
lim,
|
||||||
)
|
)
|
||||||
|
@ -452,9 +459,9 @@ select count() from
|
||||||
|
|
||||||
def totalNewForCurrentDeck(self):
|
def totalNewForCurrentDeck(self):
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from cards where id in (
|
select count() from cards where id in (
|
||||||
select id from cards where did in %s and queue = 0 limit ?)"""
|
select id from cards where did in %s and queue = {QUEUE_TYPE_NEW} limit ?)"""
|
||||||
% ids2str(self.col.decks.active()),
|
% ids2str(self.col.decks.active()),
|
||||||
self.reportLimit,
|
self.reportLimit,
|
||||||
)
|
)
|
||||||
|
@ -466,9 +473,9 @@ select id from cards where did in %s and queue = 0 limit ?)"""
|
||||||
# sub-day
|
# sub-day
|
||||||
self.lrnCount = (
|
self.lrnCount = (
|
||||||
self.col.db.scalar(
|
self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select sum(left/1000) from (select left from cards where
|
select sum(left/1000) from (select left from cards where
|
||||||
did in %s and queue = 1 and due < ? limit %d)"""
|
did in %s and queue = {QUEUE_TYPE_LRN} and due < ? limit %d)"""
|
||||||
% (self._deckLimit(), self.reportLimit),
|
% (self._deckLimit(), self.reportLimit),
|
||||||
self.dayCutoff,
|
self.dayCutoff,
|
||||||
)
|
)
|
||||||
|
@ -476,8 +483,8 @@ did in %s and queue = 1 and due < ? limit %d)"""
|
||||||
)
|
)
|
||||||
# day
|
# day
|
||||||
self.lrnCount += self.col.db.scalar(
|
self.lrnCount += self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from cards where did in %s and queue = 3
|
select count() from cards where did in %s and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN}
|
||||||
and due <= ? limit %d"""
|
and due <= ? limit %d"""
|
||||||
% (self._deckLimit(), self.reportLimit),
|
% (self._deckLimit(), self.reportLimit),
|
||||||
self.today,
|
self.today,
|
||||||
|
@ -496,9 +503,9 @@ and due <= ? limit %d"""
|
||||||
if self._lrnQueue:
|
if self._lrnQueue:
|
||||||
return True
|
return True
|
||||||
self._lrnQueue = self.col.db.all(
|
self._lrnQueue = self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select due, id from cards where
|
select due, id from cards where
|
||||||
did in %s and queue = 1 and due < :lim
|
did in %s and queue = {QUEUE_TYPE_LRN} and due < :lim
|
||||||
limit %d"""
|
limit %d"""
|
||||||
% (self._deckLimit(), self.reportLimit),
|
% (self._deckLimit(), self.reportLimit),
|
||||||
lim=self.dayCutoff,
|
lim=self.dayCutoff,
|
||||||
|
@ -528,9 +535,9 @@ limit %d"""
|
||||||
did = self._lrnDids[0]
|
did = self._lrnDids[0]
|
||||||
# fill the queue with the current did
|
# fill the queue with the current did
|
||||||
self._lrnDayQueue = self.col.db.list(
|
self._lrnDayQueue = self.col.db.list(
|
||||||
"""
|
f"""
|
||||||
select id from cards where
|
select id from cards where
|
||||||
did = ? and queue = 3 and due <= ? limit ?""",
|
did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
did,
|
did,
|
||||||
self.today,
|
self.today,
|
||||||
self.queueLimit,
|
self.queueLimit,
|
||||||
|
@ -556,25 +563,25 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
# ease 1=no, 2=yes, 3=remove
|
# ease 1=no, 2=yes, 3=remove
|
||||||
conf = self._lrnConf(card)
|
conf = self._lrnConf(card)
|
||||||
if card.odid and not card.wasNew:
|
if card.odid and not card.wasNew:
|
||||||
type = 3
|
type = REVLOG_CRAM
|
||||||
elif card.type == 2:
|
elif card.type == CARD_TYPE_REV:
|
||||||
type = 2
|
type = REVLOG_RELRN
|
||||||
else:
|
else:
|
||||||
type = 0
|
type = REVLOG_LRN
|
||||||
leaving = False
|
leaving = False
|
||||||
# lrnCount was decremented once when card was fetched
|
# lrnCount was decremented once when card was fetched
|
||||||
lastLeft = card.left
|
lastLeft = card.left
|
||||||
# immediate graduate?
|
# immediate graduate?
|
||||||
if ease == 3:
|
if ease == BUTTON_THREE:
|
||||||
self._rescheduleAsRev(card, conf, True)
|
self._rescheduleAsRev(card, conf, True)
|
||||||
leaving = True
|
leaving = True
|
||||||
# graduation time?
|
# graduation time?
|
||||||
elif ease == 2 and (card.left % 1000) - 1 <= 0:
|
elif ease == BUTTON_TWO and (card.left % 1000) - 1 <= 0:
|
||||||
self._rescheduleAsRev(card, conf, False)
|
self._rescheduleAsRev(card, conf, False)
|
||||||
leaving = True
|
leaving = True
|
||||||
else:
|
else:
|
||||||
# one step towards graduation
|
# one step towards graduation
|
||||||
if ease == 2:
|
if ease == BUTTON_TWO:
|
||||||
# decrement real left count and recalculate left today
|
# decrement real left count and recalculate left today
|
||||||
left = (card.left % 1000) - 1
|
left = (card.left % 1000) - 1
|
||||||
card.left = self._leftToday(conf["delays"], left) * 1000 + left
|
card.left = self._leftToday(conf["delays"], left) * 1000 + left
|
||||||
|
@ -601,7 +608,7 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
# if the queue is not empty and there's nothing else to do, make
|
# if the queue is not empty and there's nothing else to do, make
|
||||||
# sure we don't put it at the head of the queue and end up showing
|
# sure we don't put it at the head of the queue and end up showing
|
||||||
# it twice in a row
|
# it twice in a row
|
||||||
card.queue = 1
|
card.queue = QUEUE_TYPE_LRN
|
||||||
if self._lrnQueue and not self.revCount and not self.newCount:
|
if self._lrnQueue and not self.revCount and not self.newCount:
|
||||||
smallestDue = self._lrnQueue[0][0]
|
smallestDue = self._lrnQueue[0][0]
|
||||||
card.due = max(card.due, smallestDue + 1)
|
card.due = max(card.due, smallestDue + 1)
|
||||||
|
@ -611,7 +618,7 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
# day learn queue
|
# day learn queue
|
||||||
ahead = ((card.due - self.dayCutoff) // 86400) + 1
|
ahead = ((card.due - self.dayCutoff) // 86400) + 1
|
||||||
card.due = self.today + ahead
|
card.due = self.today + ahead
|
||||||
card.queue = 3
|
card.queue = QUEUE_TYPE_DAY_LEARN_RELEARN
|
||||||
self._logLrn(card, ease, conf, leaving, type, lastLeft)
|
self._logLrn(card, ease, conf, leaving, type, lastLeft)
|
||||||
|
|
||||||
def _delayForGrade(self, conf, left):
|
def _delayForGrade(self, conf, left):
|
||||||
|
@ -627,13 +634,13 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
return delay * 60
|
return delay * 60
|
||||||
|
|
||||||
def _lrnConf(self, card):
|
def _lrnConf(self, card):
|
||||||
if card.type == 2:
|
if card.type == CARD_TYPE_REV:
|
||||||
return self._lapseConf(card)
|
return self._lapseConf(card)
|
||||||
else:
|
else:
|
||||||
return self._newConf(card)
|
return self._newConf(card)
|
||||||
|
|
||||||
def _rescheduleAsRev(self, card, conf, early):
|
def _rescheduleAsRev(self, card, conf, early):
|
||||||
lapse = card.type == 2
|
lapse = card.type == CARD_TYPE_REV
|
||||||
if lapse:
|
if lapse:
|
||||||
if self._resched(card):
|
if self._resched(card):
|
||||||
card.due = max(self.today + 1, card.odue)
|
card.due = max(self.today + 1, card.odue)
|
||||||
|
@ -642,8 +649,8 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
card.odue = 0
|
card.odue = 0
|
||||||
else:
|
else:
|
||||||
self._rescheduleNew(card, conf, early)
|
self._rescheduleNew(card, conf, early)
|
||||||
card.queue = 2
|
card.queue = QUEUE_TYPE_REV
|
||||||
card.type = 2
|
card.type = CARD_TYPE_REV
|
||||||
# if we were dynamic, graduating means moving back to the old deck
|
# if we were dynamic, graduating means moving back to the old deck
|
||||||
resched = self._resched(card)
|
resched = self._resched(card)
|
||||||
if card.odid:
|
if card.odid:
|
||||||
|
@ -652,11 +659,11 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
card.odid = 0
|
card.odid = 0
|
||||||
# if rescheduling is off, it needs to be set back to a new card
|
# if rescheduling is off, it needs to be set back to a new card
|
||||||
if not resched and not lapse:
|
if not resched and not lapse:
|
||||||
card.queue = card.type = 0
|
card.queue = card.type = CARD_TYPE_NEW
|
||||||
card.due = self.col.nextID("pos")
|
card.due = self.col.nextID("pos")
|
||||||
|
|
||||||
def _startingLeft(self, card):
|
def _startingLeft(self, card):
|
||||||
if card.type == 2:
|
if card.type == CARD_TYPE_REV:
|
||||||
conf = self._lapseConf(card)
|
conf = self._lapseConf(card)
|
||||||
else:
|
else:
|
||||||
conf = self._lrnConf(card)
|
conf = self._lrnConf(card)
|
||||||
|
@ -678,7 +685,7 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
return ok + 1
|
return ok + 1
|
||||||
|
|
||||||
def _graduatingIvl(self, card, conf, early, adj=True):
|
def _graduatingIvl(self, card, conf, early, adj=True):
|
||||||
if card.type == 2:
|
if card.type == CARD_TYPE_REV:
|
||||||
# lapsed card being relearnt
|
# lapsed card being relearnt
|
||||||
if card.odid:
|
if card.odid:
|
||||||
if conf["resched"]:
|
if conf["resched"]:
|
||||||
|
@ -736,25 +743,28 @@ did = ? and queue = 3 and due <= ? limit ?""",
|
||||||
extra = " and did in " + ids2str(self.col.decks.allIds())
|
extra = " and did in " + ids2str(self.col.decks.allIds())
|
||||||
# review cards in relearning
|
# review cards in relearning
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"""
|
f"""
|
||||||
update cards set
|
update cards set
|
||||||
due = odue, queue = 2, mod = %d, usn = %d, odue = 0
|
due = odue, queue = {QUEUE_TYPE_REV}, mod = %d, usn = %d, odue = 0
|
||||||
where queue in (1,3) and type = 2
|
where queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_DAY_LEARN_RELEARN}) and type = {CARD_TYPE_REV}
|
||||||
%s
|
%s
|
||||||
"""
|
"""
|
||||||
% (intTime(), self.col.usn(), extra)
|
% (intTime(), self.col.usn(), extra)
|
||||||
)
|
)
|
||||||
# new cards in learning
|
# new cards in learning
|
||||||
self.forgetCards(
|
self.forgetCards(
|
||||||
self.col.db.list("select id from cards where queue in (1,3) %s" % extra)
|
self.col.db.list(
|
||||||
|
f"select id from cards where queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_DAY_LEARN_RELEARN}) %s"
|
||||||
|
% extra
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _lrnForDeck(self, did):
|
def _lrnForDeck(self, did):
|
||||||
cnt = (
|
cnt = (
|
||||||
self.col.db.scalar(
|
self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select sum(left/1000) from
|
select sum(left/1000) from
|
||||||
(select left from cards where did = ? and queue = 1 and due < ? limit ?)""",
|
(select left from cards where did = ? and queue = {QUEUE_TYPE_LRN} and due < ? limit ?)""",
|
||||||
did,
|
did,
|
||||||
intTime() + self.col.conf["collapseTime"],
|
intTime() + self.col.conf["collapseTime"],
|
||||||
self.reportLimit,
|
self.reportLimit,
|
||||||
|
@ -762,9 +772,9 @@ select sum(left/1000) from
|
||||||
or 0
|
or 0
|
||||||
)
|
)
|
||||||
return cnt + self.col.db.scalar(
|
return cnt + self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from
|
select count() from
|
||||||
(select 1 from cards where did = ? and queue = 3
|
(select 1 from cards where did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN}
|
||||||
and due <= ? limit ?)""",
|
and due <= ? limit ?)""",
|
||||||
did,
|
did,
|
||||||
self.today,
|
self.today,
|
||||||
|
@ -786,9 +796,9 @@ and due <= ? limit ?)""",
|
||||||
def _revForDeck(self, did, lim):
|
def _revForDeck(self, did, lim):
|
||||||
lim = min(lim, self.reportLimit)
|
lim = min(lim, self.reportLimit)
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from
|
select count() from
|
||||||
(select 1 from cards where did = ? and queue = 2
|
(select 1 from cards where did = ? and queue = {QUEUE_TYPE_REV}
|
||||||
and due <= ? limit ?)""",
|
and due <= ? limit ?)""",
|
||||||
did,
|
did,
|
||||||
self.today,
|
self.today,
|
||||||
|
@ -798,9 +808,9 @@ and due <= ? limit ?)""",
|
||||||
def _resetRevCount(self):
|
def _resetRevCount(self):
|
||||||
def cntFn(did, lim):
|
def cntFn(did, lim):
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from (select id from cards where
|
select count() from (select id from cards where
|
||||||
did = ? and queue = 2 and due <= ? limit %d)"""
|
did = ? and queue = {QUEUE_TYPE_REV} and due <= ? limit %d)"""
|
||||||
% lim,
|
% lim,
|
||||||
did,
|
did,
|
||||||
self.today,
|
self.today,
|
||||||
|
@ -824,9 +834,9 @@ did = ? and queue = 2 and due <= ? limit %d)"""
|
||||||
if lim:
|
if lim:
|
||||||
# fill the queue with the current did
|
# fill the queue with the current did
|
||||||
self._revQueue = self.col.db.list(
|
self._revQueue = self.col.db.list(
|
||||||
"""
|
f"""
|
||||||
select id from cards where
|
select id from cards where
|
||||||
did = ? and queue = 2 and due <= ? limit ?""",
|
did = ? and queue = {QUEUE_TYPE_REV} and due <= ? limit ?""",
|
||||||
did,
|
did,
|
||||||
self.today,
|
self.today,
|
||||||
lim,
|
lim,
|
||||||
|
@ -861,9 +871,9 @@ did = ? and queue = 2 and due <= ? limit ?""",
|
||||||
|
|
||||||
def totalRevForCurrentDeck(self):
|
def totalRevForCurrentDeck(self):
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from cards where id in (
|
select count() from cards where id in (
|
||||||
select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? limit ?)"""
|
||||||
% ids2str(self.col.decks.active()),
|
% ids2str(self.col.decks.active()),
|
||||||
self.today,
|
self.today,
|
||||||
self.reportLimit,
|
self.reportLimit,
|
||||||
|
@ -874,7 +884,7 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
|
|
||||||
def _answerRevCard(self, card, ease):
|
def _answerRevCard(self, card, ease):
|
||||||
delay = 0
|
delay = 0
|
||||||
if ease == 1:
|
if ease == BUTTON_ONE:
|
||||||
delay = self._rescheduleLapse(card)
|
delay = self._rescheduleLapse(card)
|
||||||
else:
|
else:
|
||||||
self._rescheduleRev(card, ease)
|
self._rescheduleRev(card, ease)
|
||||||
|
@ -893,7 +903,7 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
card.odue = card.due
|
card.odue = card.due
|
||||||
# if suspended as a leech, nothing to do
|
# if suspended as a leech, nothing to do
|
||||||
delay = 0
|
delay = 0
|
||||||
if self._checkLeech(card, conf) and card.queue == -1:
|
if self._checkLeech(card, conf) and card.queue == QUEUE_TYPE_SUSPENDED:
|
||||||
return delay
|
return delay
|
||||||
# if no relearning steps, nothing to do
|
# if no relearning steps, nothing to do
|
||||||
if not conf["delays"]:
|
if not conf["delays"]:
|
||||||
|
@ -907,13 +917,13 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
# queue 1
|
# queue 1
|
||||||
if card.due < self.dayCutoff:
|
if card.due < self.dayCutoff:
|
||||||
self.lrnCount += card.left // 1000
|
self.lrnCount += card.left // 1000
|
||||||
card.queue = 1
|
card.queue = QUEUE_TYPE_LRN
|
||||||
heappush(self._lrnQueue, (card.due, card.id))
|
heappush(self._lrnQueue, (card.due, card.id))
|
||||||
else:
|
else:
|
||||||
# day learn queue
|
# day learn queue
|
||||||
ahead = ((card.due - self.dayCutoff) // 86400) + 1
|
ahead = ((card.due - self.dayCutoff) // 86400) + 1
|
||||||
card.due = self.today + ahead
|
card.due = self.today + ahead
|
||||||
card.queue = 3
|
card.queue = QUEUE_TYPE_DAY_LEARN_RELEARN
|
||||||
return delay
|
return delay
|
||||||
|
|
||||||
def _nextLapseIvl(self, card, conf):
|
def _nextLapseIvl(self, card, conf):
|
||||||
|
@ -946,7 +956,7 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
card.lastIvl,
|
card.lastIvl,
|
||||||
card.factor,
|
card.factor,
|
||||||
card.timeTaken(),
|
card.timeTaken(),
|
||||||
1,
|
REVLOG_REV,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -969,11 +979,11 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
ivl4 = self._constrainedIvl(
|
ivl4 = self._constrainedIvl(
|
||||||
(card.ivl + delay) * fct * conf["ease4"], conf, ivl3
|
(card.ivl + delay) * fct * conf["ease4"], conf, ivl3
|
||||||
)
|
)
|
||||||
if ease == 2:
|
if ease == BUTTON_TWO:
|
||||||
interval = ivl2
|
interval = ivl2
|
||||||
elif ease == 3:
|
elif ease == BUTTON_THREE:
|
||||||
interval = ivl3
|
interval = ivl3
|
||||||
elif ease == 4:
|
elif ease == BUTTON_FOUR:
|
||||||
interval = ivl4
|
interval = ivl4
|
||||||
# interval capped?
|
# interval capped?
|
||||||
return min(interval, conf["maxIvl"])
|
return min(interval, conf["maxIvl"])
|
||||||
|
@ -1058,9 +1068,9 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
self.col.log(self.col.db.list("select id from cards where %s" % lim))
|
self.col.log(self.col.db.list("select id from cards where %s" % lim))
|
||||||
# move out of cram queue
|
# move out of cram queue
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"""
|
f"""
|
||||||
update cards set did = odid, queue = (case when type = 1 then 0
|
update cards set did = odid, queue = (case when type = {CARD_TYPE_LRN} then {QUEUE_TYPE_NEW}
|
||||||
else type end), type = (case when type = 1 then 0 else type end),
|
else type end), type = (case when type = {CARD_TYPE_LRN} then {CARD_TYPE_NEW} else type end),
|
||||||
due = odue, odue = 0, odid = 0, usn = ? where %s"""
|
due = odue, odue = 0, odid = 0, usn = ? where %s"""
|
||||||
% lim,
|
% lim,
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
|
@ -1088,7 +1098,7 @@ due = odue, odue = 0, odid = 0, usn = ? where %s"""
|
||||||
t = "c.due"
|
t = "c.due"
|
||||||
elif o == DYN_DUEPRIORITY:
|
elif o == DYN_DUEPRIORITY:
|
||||||
t = (
|
t = (
|
||||||
"(case when queue=2 and due <= %d then (ivl / cast(%d-due+0.001 as real)) else 100000+due end)"
|
f"(case when queue={QUEUE_TYPE_REV} and due <= %d then (ivl / cast(%d-due+0.001 as real)) else 100000+due end)"
|
||||||
% (self.today, self.today)
|
% (self.today, self.today)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -1106,9 +1116,9 @@ due = odue, odue = 0, odid = 0, usn = ? where %s"""
|
||||||
data.append((did, -100000 + c, u, id))
|
data.append((did, -100000 + c, u, id))
|
||||||
# due reviews stay in the review queue. careful: can't use
|
# due reviews stay in the review queue. careful: can't use
|
||||||
# "odid or did", as sqlite converts to boolean
|
# "odid or did", as sqlite converts to boolean
|
||||||
queue = """
|
queue = f"""
|
||||||
(case when type=2 and (case when odue then odue <= %d else due <= %d end)
|
(case when type={CARD_TYPE_REV} and (case when odue then odue <= %d else due <= %d end)
|
||||||
then 2 else 0 end)"""
|
then {QUEUE_TYPE_REV} else {QUEUE_TYPE_NEW} end)"""
|
||||||
queue %= (self.today, self.today)
|
queue %= (self.today, self.today)
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
"""
|
"""
|
||||||
|
@ -1121,7 +1131,7 @@ did = ?, queue = %s, due = ?, usn = ? where id = ?"""
|
||||||
)
|
)
|
||||||
|
|
||||||
def _dynIvlBoost(self, card):
|
def _dynIvlBoost(self, card):
|
||||||
assert card.odid and card.type == 2
|
assert card.odid and card.type == CARD_TYPE_REV
|
||||||
assert card.factor
|
assert card.factor
|
||||||
elapsed = card.ivl - (card.odue - self.today)
|
elapsed = card.ivl - (card.odue - self.today)
|
||||||
factor = ((card.factor / 1000) + 1.2) / 2
|
factor = ((card.factor / 1000) + 1.2) / 2
|
||||||
|
@ -1145,14 +1155,14 @@ did = ?, queue = %s, due = ?, usn = ? where id = ?"""
|
||||||
f.flush()
|
f.flush()
|
||||||
# handle
|
# handle
|
||||||
a = conf["leechAction"]
|
a = conf["leechAction"]
|
||||||
if a == 0:
|
if a == LEECH_SUSPEND:
|
||||||
# if it has an old due, remove it from cram/relearning
|
# if it has an old due, remove it from cram/relearning
|
||||||
if card.odue:
|
if card.odue:
|
||||||
card.due = card.odue
|
card.due = card.odue
|
||||||
if card.odid:
|
if card.odid:
|
||||||
card.did = card.odid
|
card.did = card.odid
|
||||||
card.odue = card.odid = 0
|
card.odue = card.odid = 0
|
||||||
card.queue = -1
|
card.queue = QUEUE_TYPE_SUSPENDED
|
||||||
# notify UI
|
# notify UI
|
||||||
hooks.card_did_leech(card)
|
hooks.card_did_leech(card)
|
||||||
return True
|
return True
|
||||||
|
@ -1311,7 +1321,7 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
"True if there are any rev cards due."
|
"True if there are any rev cards due."
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
(
|
(
|
||||||
"select 1 from cards where did in %s and queue = 2 "
|
f"select 1 from cards where did in %s and queue = {QUEUE_TYPE_REV} "
|
||||||
"and due <= ? limit 1"
|
"and due <= ? limit 1"
|
||||||
)
|
)
|
||||||
% self._deckLimit(),
|
% self._deckLimit(),
|
||||||
|
@ -1321,14 +1331,18 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
def newDue(self):
|
def newDue(self):
|
||||||
"True if there are any new cards due."
|
"True if there are any new cards due."
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
("select 1 from cards where did in %s and queue = 0 " "limit 1")
|
(
|
||||||
|
f"select 1 from cards where did in %s and queue = {QUEUE_TYPE_NEW} "
|
||||||
|
"limit 1"
|
||||||
|
)
|
||||||
% self._deckLimit()
|
% self._deckLimit()
|
||||||
)
|
)
|
||||||
|
|
||||||
def haveBuried(self):
|
def haveBuried(self):
|
||||||
sdids = ids2str(self.col.decks.active())
|
sdids = ids2str(self.col.decks.active())
|
||||||
cnt = self.col.db.scalar(
|
cnt = self.col.db.scalar(
|
||||||
"select 1 from cards where queue = -2 and did in %s limit 1" % sdids
|
f"select 1 from cards where queue = {QUEUE_TYPE_SIBLING_BURIED} and did in %s limit 1"
|
||||||
|
% sdids
|
||||||
)
|
)
|
||||||
return not not cnt
|
return not not cnt
|
||||||
|
|
||||||
|
@ -1347,9 +1361,9 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
|
|
||||||
def nextIvl(self, card, ease):
|
def nextIvl(self, card, ease):
|
||||||
"Return the next interval for CARD, in seconds."
|
"Return the next interval for CARD, in seconds."
|
||||||
if card.queue in (0, 1, 3):
|
if card.queue in (QUEUE_TYPE_NEW, QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
||||||
return self._nextLrnIvl(card, ease)
|
return self._nextLrnIvl(card, ease)
|
||||||
elif ease == 1:
|
elif ease == BUTTON_ONE:
|
||||||
# lapsed
|
# lapsed
|
||||||
conf = self._lapseConf(card)
|
conf = self._lapseConf(card)
|
||||||
if conf["delays"]:
|
if conf["delays"]:
|
||||||
|
@ -1364,10 +1378,10 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
if card.queue == 0:
|
if card.queue == 0:
|
||||||
card.left = self._startingLeft(card)
|
card.left = self._startingLeft(card)
|
||||||
conf = self._lrnConf(card)
|
conf = self._lrnConf(card)
|
||||||
if ease == 1:
|
if ease == BUTTON_ONE:
|
||||||
# fail
|
# fail
|
||||||
return self._delayForGrade(conf, len(conf["delays"]))
|
return self._delayForGrade(conf, len(conf["delays"]))
|
||||||
elif ease == 3:
|
elif ease == BUTTON_THREE:
|
||||||
# early removal
|
# early removal
|
||||||
if not self._resched(card):
|
if not self._resched(card):
|
||||||
return 0
|
return 0
|
||||||
|
@ -1391,7 +1405,8 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
self.remFromDyn(ids)
|
self.remFromDyn(ids)
|
||||||
self.removeLrn(ids)
|
self.removeLrn(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set queue=-1,mod=?,usn=? where id in " + ids2str(ids),
|
f"update cards set queue={QUEUE_TYPE_SUSPENDED},mod=?,usn=? where id in "
|
||||||
|
+ ids2str(ids),
|
||||||
intTime(),
|
intTime(),
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
)
|
)
|
||||||
|
@ -1401,7 +1416,7 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
self.col.log(ids)
|
self.col.log(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set queue=type,mod=?,usn=? "
|
"update cards set queue=type,mod=?,usn=? "
|
||||||
"where queue = -1 and id in " + ids2str(ids),
|
f"where queue = {QUEUE_TYPE_SUSPENDED} and id in " + ids2str(ids),
|
||||||
intTime(),
|
intTime(),
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
)
|
)
|
||||||
|
@ -1411,8 +1426,8 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
self.remFromDyn(cids)
|
self.remFromDyn(cids)
|
||||||
self.removeLrn(cids)
|
self.removeLrn(cids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"""
|
f"""
|
||||||
update cards set queue=-2,mod=?,usn=? where id in """
|
update cards set queue={QUEUE_TYPE_SIBLING_BURIED},mod=?,usn=? where id in """
|
||||||
+ ids2str(cids),
|
+ ids2str(cids),
|
||||||
intTime(),
|
intTime(),
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
|
@ -1436,14 +1451,14 @@ update cards set queue=-2,mod=?,usn=? where id in """
|
||||||
buryRev = rconf.get("bury", True)
|
buryRev = rconf.get("bury", True)
|
||||||
# loop through and remove from queues
|
# loop through and remove from queues
|
||||||
for cid, queue in self.col.db.execute(
|
for cid, queue in self.col.db.execute(
|
||||||
"""
|
f"""
|
||||||
select id, queue from cards where nid=? and id!=?
|
select id, queue from cards where nid=? and id!=?
|
||||||
and (queue=0 or (queue=2 and due<=?))""",
|
and (queue={QUEUE_TYPE_NEW} or (queue={QUEUE_TYPE_REV} and due<=?))""",
|
||||||
card.nid,
|
card.nid,
|
||||||
card.id,
|
card.id,
|
||||||
self.today,
|
self.today,
|
||||||
):
|
):
|
||||||
if queue == 2:
|
if queue == QUEUE_TYPE_REV:
|
||||||
if buryRev:
|
if buryRev:
|
||||||
toBury.append(cid)
|
toBury.append(cid)
|
||||||
# if bury disabled, we still discard to give same-day spacing
|
# if bury disabled, we still discard to give same-day spacing
|
||||||
|
@ -1462,7 +1477,8 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
# then bury
|
# then bury
|
||||||
if toBury:
|
if toBury:
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set queue=-2,mod=?,usn=? where id in " + ids2str(toBury),
|
f"update cards set queue={QUEUE_TYPE_SIBLING_BURIED},mod=?,usn=? where id in "
|
||||||
|
+ ids2str(toBury),
|
||||||
intTime(),
|
intTime(),
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
)
|
)
|
||||||
|
@ -1475,11 +1491,14 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
"Put cards at the end of the new queue."
|
"Put cards at the end of the new queue."
|
||||||
self.remFromDyn(ids)
|
self.remFromDyn(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set type=0,queue=0,ivl=0,due=0,odue=0,factor=?"
|
f"update cards set type={CARD_TYPE_NEW},queue={QUEUE_TYPE_NEW},ivl=0,due=0,odue=0,factor=?"
|
||||||
" where id in " + ids2str(ids),
|
" where id in " + ids2str(ids),
|
||||||
STARTING_FACTOR,
|
STARTING_FACTOR,
|
||||||
)
|
)
|
||||||
pmax = self.col.db.scalar("select max(due) from cards where type=0") or 0
|
pmax = (
|
||||||
|
self.col.db.scalar(f"select max(due) from cards where type={CARD_TYPE_NEW}")
|
||||||
|
or 0
|
||||||
|
)
|
||||||
# takes care of mod + usn
|
# takes care of mod + usn
|
||||||
self.sortCards(ids, start=pmax + 1)
|
self.sortCards(ids, start=pmax + 1)
|
||||||
self.col.log(ids)
|
self.col.log(ids)
|
||||||
|
@ -1503,8 +1522,8 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
)
|
)
|
||||||
self.remFromDyn(ids)
|
self.remFromDyn(ids)
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
"""
|
f"""
|
||||||
update cards set type=2,queue=2,ivl=:ivl,due=:due,odue=0,
|
update cards set type={CARD_TYPE_REV},queue={QUEUE_TYPE_REV},ivl=:ivl,due=:due,odue=0,
|
||||||
usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
||||||
d,
|
d,
|
||||||
)
|
)
|
||||||
|
@ -1515,11 +1534,12 @@ usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
||||||
sids = ids2str(ids)
|
sids = ids2str(ids)
|
||||||
# we want to avoid resetting due number of existing new cards on export
|
# we want to avoid resetting due number of existing new cards on export
|
||||||
nonNew = self.col.db.list(
|
nonNew = self.col.db.list(
|
||||||
"select id from cards where id in %s and (queue != 0 or type != 0)" % sids
|
f"select id from cards where id in %s and (queue != {QUEUE_TYPE_NEW} or type != {CARD_TYPE_NEW})"
|
||||||
|
% sids
|
||||||
)
|
)
|
||||||
# reset all cards
|
# reset all cards
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set reps=0,lapses=0,odid=0,odue=0,queue=0"
|
f"update cards set reps=0,lapses=0,odid=0,odue=0,queue={QUEUE_TYPE_NEW}"
|
||||||
" where id in %s" % sids
|
" where id in %s" % sids
|
||||||
)
|
)
|
||||||
# and forget any non-new cards, changing their due numbers
|
# and forget any non-new cards, changing their due numbers
|
||||||
|
@ -1553,16 +1573,16 @@ usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
||||||
# shift?
|
# shift?
|
||||||
if shift:
|
if shift:
|
||||||
low = self.col.db.scalar(
|
low = self.col.db.scalar(
|
||||||
"select min(due) from cards where due >= ? and type = 0 "
|
f"select min(due) from cards where due >= ? and type = {CARD_TYPE_NEW} "
|
||||||
"and id not in %s" % scids,
|
"and id not in %s" % scids,
|
||||||
start,
|
start,
|
||||||
)
|
)
|
||||||
if low is not None:
|
if low is not None:
|
||||||
shiftby = high - low + 1
|
shiftby = high - low + 1
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"""
|
f"""
|
||||||
update cards set mod=?, usn=?, due=due+? where id not in %s
|
update cards set mod=?, usn=?, due=due+? where id not in %s
|
||||||
and due >= ? and queue = 0"""
|
and due >= ? and queue = {QUEUE_TYPE_NEW}"""
|
||||||
% scids,
|
% scids,
|
||||||
now,
|
now,
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
|
@ -1572,7 +1592,7 @@ and due >= ? and queue = 0"""
|
||||||
# reorder cards
|
# reorder cards
|
||||||
d = []
|
d = []
|
||||||
for id, nid in self.col.db.execute(
|
for id, nid in self.col.db.execute(
|
||||||
"select id, nid from cards where type = 0 and id in " + scids
|
f"select id, nid from cards where type = {CARD_TYPE_NEW} and id in " + scids
|
||||||
):
|
):
|
||||||
d.append(dict(now=now, due=due[nid], usn=self.col.usn(), cid=id))
|
d.append(dict(now=now, due=due[nid], usn=self.col.usn(), cid=id))
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
|
|
|
@ -22,13 +22,9 @@ from anki.rsbackend import SchedTimingToday
|
||||||
from anki.utils import fmtTimeSpan, ids2str, intTime
|
from anki.utils import fmtTimeSpan, ids2str, intTime
|
||||||
|
|
||||||
# card types: 0=new, 1=lrn, 2=rev, 3=relrn
|
# card types: 0=new, 1=lrn, 2=rev, 3=relrn
|
||||||
CARD_TYPE_RELEARNING = 3
|
|
||||||
# queue types: 0=new, 1=(re)lrn, 2=rev, 3=day (re)lrn,
|
# queue types: 0=new, 1=(re)lrn, 2=rev, 3=day (re)lrn,
|
||||||
# 4=preview, -1=suspended, -2=sibling buried, -3=manually buried
|
# 4=preview, -1=suspended, -2=sibling buried, -3=manually buried
|
||||||
QUEUE_TYPE_PREVIEW = 4
|
|
||||||
QUEUE_TYPE_DAY_LEARN_RELEARN = 3
|
|
||||||
QUEUE_TYPE_SIBLING_BURIED = -2
|
|
||||||
QUEUE_TYPE_MANUALLY_BURIED = -3
|
|
||||||
# revlog types: 0=lrn, 1=rev, 2=relrn, 3=early review
|
# revlog types: 0=lrn, 1=rev, 2=relrn, 3=early review
|
||||||
# positive revlog intervals are in days (rev), negative in seconds (lrn)
|
# positive revlog intervals are in days (rev), negative in seconds (lrn)
|
||||||
# odue/odid store original due/did when cards moved to filtered deck
|
# odue/odid store original due/did when cards moved to filtered deck
|
||||||
|
@ -95,18 +91,18 @@ class Scheduler:
|
||||||
|
|
||||||
card.reps += 1
|
card.reps += 1
|
||||||
|
|
||||||
if card.queue == 0:
|
if card.queue == QUEUE_TYPE_NEW:
|
||||||
# came from the new queue, move to learning
|
# came from the new queue, move to learning
|
||||||
card.queue = 1
|
card.queue = QUEUE_TYPE_LRN
|
||||||
card.type = 1
|
card.type = CARD_TYPE_LRN
|
||||||
# init reps to graduation
|
# init reps to graduation
|
||||||
card.left = self._startingLeft(card)
|
card.left = self._startingLeft(card)
|
||||||
# update daily limit
|
# update daily limit
|
||||||
self._updateStats(card, "new")
|
self._updateStats(card, "new")
|
||||||
|
|
||||||
if card.queue in (1, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
||||||
self._answerLrnCard(card, ease)
|
self._answerLrnCard(card, ease)
|
||||||
elif card.queue == 2:
|
elif card.queue == QUEUE_TYPE_REV:
|
||||||
self._answerRevCard(card, ease)
|
self._answerRevCard(card, ease)
|
||||||
# update daily limit
|
# update daily limit
|
||||||
self._updateStats(card, "rev")
|
self._updateStats(card, "rev")
|
||||||
|
@ -121,12 +117,13 @@ class Scheduler:
|
||||||
def _answerCardPreview(self, card: Card, ease: int) -> None:
|
def _answerCardPreview(self, card: Card, ease: int) -> None:
|
||||||
assert 1 <= ease <= 2
|
assert 1 <= ease <= 2
|
||||||
|
|
||||||
if ease == 1:
|
if ease == BUTTON_ONE:
|
||||||
# repeat after delay
|
# repeat after delay
|
||||||
card.queue = QUEUE_TYPE_PREVIEW
|
card.queue = QUEUE_TYPE_PREVIEW
|
||||||
card.due = intTime() + self._previewDelay(card)
|
card.due = intTime() + self._previewDelay(card)
|
||||||
self.lrnCount += 1
|
self.lrnCount += 1
|
||||||
else:
|
else:
|
||||||
|
# BUTTON_TWO
|
||||||
# restore original card state and remove from filtered deck
|
# restore original card state and remove from filtered deck
|
||||||
self._restorePreviewCard(card)
|
self._restorePreviewCard(card)
|
||||||
self._removeFromFiltered(card)
|
self._removeFromFiltered(card)
|
||||||
|
@ -142,9 +139,9 @@ class Scheduler:
|
||||||
"Return counts over next DAYS. Includes today."
|
"Return counts over next DAYS. Includes today."
|
||||||
daysd = dict(
|
daysd = dict(
|
||||||
self.col.db.all(
|
self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select due, count() from cards
|
select due, count() from cards
|
||||||
where did in %s and queue = 2
|
where did in %s and queue = {QUEUE_TYPE_REV}
|
||||||
and due between ? and ?
|
and due between ? and ?
|
||||||
group by due
|
group by due
|
||||||
order by due"""
|
order by due"""
|
||||||
|
@ -368,9 +365,9 @@ order by due"""
|
||||||
|
|
||||||
def _resetNewCount(self) -> None:
|
def _resetNewCount(self) -> None:
|
||||||
cntFn = lambda did, lim: self.col.db.scalar(
|
cntFn = lambda did, lim: self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from (select 1 from cards where
|
select count() from (select 1 from cards where
|
||||||
did = ? and queue = 0 limit ?)""",
|
did = ? and queue = {QUEUE_TYPE_NEW} limit ?)""",
|
||||||
did,
|
did,
|
||||||
lim,
|
lim,
|
||||||
)
|
)
|
||||||
|
@ -393,8 +390,8 @@ did = ? and queue = 0 limit ?)""",
|
||||||
if lim:
|
if lim:
|
||||||
# fill the queue with the current did
|
# fill the queue with the current did
|
||||||
self._newQueue = self.col.db.list(
|
self._newQueue = self.col.db.list(
|
||||||
"""
|
f"""
|
||||||
select id from cards where did = ? and queue = 0 order by due,ord limit ?""",
|
select id from cards where did = ? and queue = {QUEUE_TYPE_NEW} order by due,ord limit ?""",
|
||||||
did,
|
did,
|
||||||
lim,
|
lim,
|
||||||
)
|
)
|
||||||
|
@ -462,9 +459,9 @@ did = ? and queue = 0 limit ?)""",
|
||||||
return 0
|
return 0
|
||||||
lim = min(lim, self.reportLimit)
|
lim = min(lim, self.reportLimit)
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from
|
select count() from
|
||||||
(select 1 from cards where did = ? and queue = 0 limit ?)""",
|
(select 1 from cards where did = ? and queue = {QUEUE_TYPE_NEW} limit ?)""",
|
||||||
did,
|
did,
|
||||||
lim,
|
lim,
|
||||||
)
|
)
|
||||||
|
@ -478,9 +475,9 @@ select count() from
|
||||||
|
|
||||||
def totalNewForCurrentDeck(self) -> Any:
|
def totalNewForCurrentDeck(self) -> Any:
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from cards where id in (
|
select count() from cards where id in (
|
||||||
select id from cards where did in %s and queue = 0 limit ?)"""
|
select id from cards where did in %s and queue = {QUEUE_TYPE_NEW} limit ?)"""
|
||||||
% self._deckLimit(),
|
% self._deckLimit(),
|
||||||
self.reportLimit,
|
self.reportLimit,
|
||||||
)
|
)
|
||||||
|
@ -504,8 +501,8 @@ select id from cards where did in %s and queue = 0 limit ?)"""
|
||||||
# sub-day
|
# sub-day
|
||||||
self.lrnCount = (
|
self.lrnCount = (
|
||||||
self.col.db.scalar(
|
self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from cards where did in %s and queue = 1
|
select count() from cards where did in %s and queue = {QUEUE_TYPE_LRN}
|
||||||
and due < ?"""
|
and due < ?"""
|
||||||
% (self._deckLimit()),
|
% (self._deckLimit()),
|
||||||
self._lrnCutoff,
|
self._lrnCutoff,
|
||||||
|
@ -545,7 +542,7 @@ select count() from cards where did in %s and queue = {QUEUE_TYPE_PREVIEW}
|
||||||
self._lrnQueue = self.col.db.all(
|
self._lrnQueue = self.col.db.all(
|
||||||
f"""
|
f"""
|
||||||
select due, id from cards where
|
select due, id from cards where
|
||||||
did in %s and queue in (1,{QUEUE_TYPE_PREVIEW}) and due < :lim
|
did in %s and queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_PREVIEW}) and due < :lim
|
||||||
limit %d"""
|
limit %d"""
|
||||||
% (self._deckLimit(), self.reportLimit),
|
% (self._deckLimit(), self.reportLimit),
|
||||||
lim=cutoff,
|
lim=cutoff,
|
||||||
|
@ -606,28 +603,28 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
|
|
||||||
def _answerLrnCard(self, card: Card, ease: int) -> None:
|
def _answerLrnCard(self, card: Card, ease: int) -> None:
|
||||||
conf = self._lrnConf(card)
|
conf = self._lrnConf(card)
|
||||||
if card.type in (2, CARD_TYPE_RELEARNING):
|
if card.type in (CARD_TYPE_REV, CARD_TYPE_RELEARNING):
|
||||||
type = 2
|
type = REVLOG_RELRN
|
||||||
else:
|
else:
|
||||||
type = 0
|
type = REVLOG_LRN
|
||||||
# lrnCount was decremented once when card was fetched
|
# lrnCount was decremented once when card was fetched
|
||||||
lastLeft = card.left
|
lastLeft = card.left
|
||||||
|
|
||||||
leaving = False
|
leaving = False
|
||||||
|
|
||||||
# immediate graduate?
|
# immediate graduate?
|
||||||
if ease == 4:
|
if ease == BUTTON_FOUR:
|
||||||
self._rescheduleAsRev(card, conf, True)
|
self._rescheduleAsRev(card, conf, True)
|
||||||
leaving = True
|
leaving = True
|
||||||
# next step?
|
# next step?
|
||||||
elif ease == 3:
|
elif ease == BUTTON_THREE:
|
||||||
# graduation time?
|
# graduation time?
|
||||||
if (card.left % 1000) - 1 <= 0:
|
if (card.left % 1000) - 1 <= 0:
|
||||||
self._rescheduleAsRev(card, conf, False)
|
self._rescheduleAsRev(card, conf, False)
|
||||||
leaving = True
|
leaving = True
|
||||||
else:
|
else:
|
||||||
self._moveToNextStep(card, conf)
|
self._moveToNextStep(card, conf)
|
||||||
elif ease == 2:
|
elif ease == BUTTON_TWO:
|
||||||
self._repeatStep(card, conf)
|
self._repeatStep(card, conf)
|
||||||
else:
|
else:
|
||||||
# back to first step
|
# back to first step
|
||||||
|
@ -673,7 +670,7 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
maxExtra = min(300, int(delay * 0.25))
|
maxExtra = min(300, int(delay * 0.25))
|
||||||
fuzz = random.randrange(0, maxExtra)
|
fuzz = random.randrange(0, maxExtra)
|
||||||
card.due = min(self.dayCutoff - 1, card.due + fuzz)
|
card.due = min(self.dayCutoff - 1, card.due + fuzz)
|
||||||
card.queue = 1
|
card.queue = QUEUE_TYPE_LRN
|
||||||
if card.due < (intTime() + self.col.conf["collapseTime"]):
|
if card.due < (intTime() + self.col.conf["collapseTime"]):
|
||||||
self.lrnCount += 1
|
self.lrnCount += 1
|
||||||
# if the queue is not empty and there's nothing else to do, make
|
# if the queue is not empty and there's nothing else to do, make
|
||||||
|
@ -714,13 +711,13 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
return avg
|
return avg
|
||||||
|
|
||||||
def _lrnConf(self, card: Card) -> Any:
|
def _lrnConf(self, card: Card) -> Any:
|
||||||
if card.type in (2, CARD_TYPE_RELEARNING):
|
if card.type in (CARD_TYPE_REV, CARD_TYPE_RELEARNING):
|
||||||
return self._lapseConf(card)
|
return self._lapseConf(card)
|
||||||
else:
|
else:
|
||||||
return self._newConf(card)
|
return self._newConf(card)
|
||||||
|
|
||||||
def _rescheduleAsRev(self, card: Card, conf: Dict[str, Any], early: bool) -> None:
|
def _rescheduleAsRev(self, card: Card, conf: Dict[str, Any], early: bool) -> None:
|
||||||
lapse = card.type in (2, CARD_TYPE_RELEARNING)
|
lapse = card.type in (CARD_TYPE_REV, CARD_TYPE_RELEARNING)
|
||||||
|
|
||||||
if lapse:
|
if lapse:
|
||||||
self._rescheduleGraduatingLapse(card, early)
|
self._rescheduleGraduatingLapse(card, early)
|
||||||
|
@ -735,8 +732,8 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
if early:
|
if early:
|
||||||
card.ivl += 1
|
card.ivl += 1
|
||||||
card.due = self.today + card.ivl
|
card.due = self.today + card.ivl
|
||||||
card.queue = 2
|
card.queue = QUEUE_TYPE_REV
|
||||||
card.type = 2
|
card.type = CARD_TYPE_REV
|
||||||
|
|
||||||
def _startingLeft(self, card: Card) -> int:
|
def _startingLeft(self, card: Card) -> int:
|
||||||
if card.type == CARD_TYPE_RELEARNING:
|
if card.type == CARD_TYPE_RELEARNING:
|
||||||
|
@ -768,7 +765,7 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
def _graduatingIvl(
|
def _graduatingIvl(
|
||||||
self, card: Card, conf: Dict[str, Any], early: bool, fuzz: bool = True
|
self, card: Card, conf: Dict[str, Any], early: bool, fuzz: bool = True
|
||||||
) -> Any:
|
) -> Any:
|
||||||
if card.type in (2, CARD_TYPE_RELEARNING):
|
if card.type in (CARD_TYPE_REV, CARD_TYPE_RELEARNING):
|
||||||
bonus = early and 1 or 0
|
bonus = early and 1 or 0
|
||||||
return card.ivl + bonus
|
return card.ivl + bonus
|
||||||
if not early:
|
if not early:
|
||||||
|
@ -786,7 +783,7 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
card.ivl = self._graduatingIvl(card, conf, early)
|
card.ivl = self._graduatingIvl(card, conf, early)
|
||||||
card.due = self.today + card.ivl
|
card.due = self.today + card.ivl
|
||||||
card.factor = conf["initialFactor"]
|
card.factor = conf["initialFactor"]
|
||||||
card.type = card.queue = 2
|
card.type = card.queue = QUEUE_TYPE_REV
|
||||||
|
|
||||||
def _logLrn(
|
def _logLrn(
|
||||||
self,
|
self,
|
||||||
|
@ -801,7 +798,7 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
if leaving:
|
if leaving:
|
||||||
ivl = card.ivl
|
ivl = card.ivl
|
||||||
else:
|
else:
|
||||||
if ease == 2:
|
if ease == BUTTON_TWO:
|
||||||
ivl = -self._delayForRepeatingGrade(conf, card.left)
|
ivl = -self._delayForRepeatingGrade(conf, card.left)
|
||||||
else:
|
else:
|
||||||
ivl = -self._delayForGrade(conf, card.left)
|
ivl = -self._delayForGrade(conf, card.left)
|
||||||
|
@ -830,9 +827,9 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
|
||||||
def _lrnForDeck(self, did: int) -> Any:
|
def _lrnForDeck(self, did: int) -> Any:
|
||||||
cnt = (
|
cnt = (
|
||||||
self.col.db.scalar(
|
self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from
|
select count() from
|
||||||
(select null from cards where did = ? and queue = 1 and due < ? limit ?)""",
|
(select null from cards where did = ? and queue = {QUEUE_TYPE_LRN} and due < ? limit ?)""",
|
||||||
did,
|
did,
|
||||||
intTime() + self.col.conf["collapseTime"],
|
intTime() + self.col.conf["collapseTime"],
|
||||||
self.reportLimit,
|
self.reportLimit,
|
||||||
|
@ -883,9 +880,9 @@ and due <= ? limit ?)""",
|
||||||
dids = [did] + self.col.decks.childDids(did, childMap)
|
dids = [did] + self.col.decks.childDids(did, childMap)
|
||||||
lim = min(lim, self.reportLimit)
|
lim = min(lim, self.reportLimit)
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from
|
select count() from
|
||||||
(select 1 from cards where did in %s and queue = 2
|
(select 1 from cards where did in %s and queue = {QUEUE_TYPE_REV}
|
||||||
and due <= ? limit ?)"""
|
and due <= ? limit ?)"""
|
||||||
% ids2str(dids),
|
% ids2str(dids),
|
||||||
self.today,
|
self.today,
|
||||||
|
@ -895,9 +892,9 @@ and due <= ? limit ?)"""
|
||||||
def _resetRevCount(self) -> None:
|
def _resetRevCount(self) -> None:
|
||||||
lim = self._currentRevLimit()
|
lim = self._currentRevLimit()
|
||||||
self.revCount = self.col.db.scalar(
|
self.revCount = self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from (select id from cards where
|
select count() from (select id from cards where
|
||||||
did in %s and queue = 2 and due <= ? limit ?)"""
|
did in %s and queue = {QUEUE_TYPE_REV} and due <= ? limit ?)"""
|
||||||
% self._deckLimit(),
|
% self._deckLimit(),
|
||||||
self.today,
|
self.today,
|
||||||
lim,
|
lim,
|
||||||
|
@ -916,9 +913,9 @@ did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
lim = min(self.queueLimit, self._currentRevLimit())
|
lim = min(self.queueLimit, self._currentRevLimit())
|
||||||
if lim:
|
if lim:
|
||||||
self._revQueue = self.col.db.list(
|
self._revQueue = self.col.db.list(
|
||||||
"""
|
f"""
|
||||||
select id from cards where
|
select id from cards where
|
||||||
did in %s and queue = 2 and due <= ?
|
did in %s and queue = {QUEUE_TYPE_REV} and due <= ?
|
||||||
order by due, random()
|
order by due, random()
|
||||||
limit ?"""
|
limit ?"""
|
||||||
% self._deckLimit(),
|
% self._deckLimit(),
|
||||||
|
@ -946,9 +943,9 @@ limit ?"""
|
||||||
|
|
||||||
def totalRevForCurrentDeck(self) -> int:
|
def totalRevForCurrentDeck(self) -> int:
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from cards where id in (
|
select count() from cards where id in (
|
||||||
select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? limit ?)"""
|
||||||
% self._deckLimit(),
|
% self._deckLimit(),
|
||||||
self.today,
|
self.today,
|
||||||
self.reportLimit,
|
self.reportLimit,
|
||||||
|
@ -960,9 +957,9 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
def _answerRevCard(self, card: Card, ease: int) -> None:
|
def _answerRevCard(self, card: Card, ease: int) -> None:
|
||||||
delay = 0
|
delay = 0
|
||||||
early = bool(card.odid and (card.odue > self.today))
|
early = bool(card.odid and (card.odue > self.today))
|
||||||
type = early and 3 or 1
|
type = early and REVLOG_CRAM or REVLOG_REV
|
||||||
|
|
||||||
if ease == 1:
|
if ease == BUTTON_ONE:
|
||||||
delay = self._rescheduleLapse(card)
|
delay = self._rescheduleLapse(card)
|
||||||
else:
|
else:
|
||||||
self._rescheduleRev(card, ease, early)
|
self._rescheduleRev(card, ease, early)
|
||||||
|
@ -976,7 +973,7 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
card.lapses += 1
|
card.lapses += 1
|
||||||
card.factor = max(1300, card.factor - 200)
|
card.factor = max(1300, card.factor - 200)
|
||||||
|
|
||||||
suspended = self._checkLeech(card, conf) and card.queue == -1
|
suspended = self._checkLeech(card, conf) and card.queue == QUEUE_TYPE_SUSPENDED
|
||||||
|
|
||||||
if conf["delays"] and not suspended:
|
if conf["delays"] and not suspended:
|
||||||
card.type = CARD_TYPE_RELEARNING
|
card.type = CARD_TYPE_RELEARNING
|
||||||
|
@ -987,7 +984,7 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
self._rescheduleAsRev(card, conf, early=False)
|
self._rescheduleAsRev(card, conf, early=False)
|
||||||
# need to reset the queue after rescheduling
|
# need to reset the queue after rescheduling
|
||||||
if suspended:
|
if suspended:
|
||||||
card.queue = -1
|
card.queue = QUEUE_TYPE_SUSPENDED
|
||||||
delay = 0
|
delay = 0
|
||||||
|
|
||||||
return delay
|
return delay
|
||||||
|
@ -1047,11 +1044,11 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
else:
|
else:
|
||||||
hardMin = 0
|
hardMin = 0
|
||||||
ivl2 = self._constrainedIvl(card.ivl * hardFactor, conf, hardMin, fuzz)
|
ivl2 = self._constrainedIvl(card.ivl * hardFactor, conf, hardMin, fuzz)
|
||||||
if ease == 2:
|
if ease == BUTTON_TWO:
|
||||||
return ivl2
|
return ivl2
|
||||||
|
|
||||||
ivl3 = self._constrainedIvl((card.ivl + delay // 2) * fct, conf, ivl2, fuzz)
|
ivl3 = self._constrainedIvl((card.ivl + delay // 2) * fct, conf, ivl2, fuzz)
|
||||||
if ease == 3:
|
if ease == BUTTON_THREE:
|
||||||
return ivl3
|
return ivl3
|
||||||
|
|
||||||
ivl4 = self._constrainedIvl(
|
ivl4 = self._constrainedIvl(
|
||||||
|
@ -1101,7 +1098,7 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
|
|
||||||
# next interval for card when answered early+correctly
|
# next interval for card when answered early+correctly
|
||||||
def _earlyReviewIvl(self, card: Card, ease: int) -> int:
|
def _earlyReviewIvl(self, card: Card, ease: int) -> int:
|
||||||
assert card.odid and card.type == 2
|
assert card.odid and card.type == CARD_TYPE_REV
|
||||||
assert card.factor
|
assert card.factor
|
||||||
assert ease > 1
|
assert ease > 1
|
||||||
|
|
||||||
|
@ -1113,14 +1110,14 @@ select id from cards where did in %s and queue = 2 and due <= ? limit ?)"""
|
||||||
# early 3/4 reviews shouldn't decrease previous interval
|
# early 3/4 reviews shouldn't decrease previous interval
|
||||||
minNewIvl = 1
|
minNewIvl = 1
|
||||||
|
|
||||||
if ease == 2:
|
if ease == BUTTON_TWO:
|
||||||
factor = conf.get("hardFactor", 1.2)
|
factor = conf.get("hardFactor", 1.2)
|
||||||
# hard cards shouldn't have their interval decreased by more than 50%
|
# hard cards shouldn't have their interval decreased by more than 50%
|
||||||
# of the normal factor
|
# of the normal factor
|
||||||
minNewIvl = factor / 2
|
minNewIvl = factor / 2
|
||||||
elif ease == 3:
|
elif ease == BUTTON_THREE:
|
||||||
factor = card.factor / 1000
|
factor = card.factor / 1000
|
||||||
else: # ease == 4:
|
else: # ease == BUTTON_FOUR:
|
||||||
factor = card.factor / 1000
|
factor = card.factor / 1000
|
||||||
ease4 = conf["ease4"]
|
ease4 = conf["ease4"]
|
||||||
# 1.3 -> 1.15
|
# 1.3 -> 1.15
|
||||||
|
@ -1213,7 +1210,7 @@ due = (case when odue>0 then odue else due end), odue = 0, odid = 0, usn = ? whe
|
||||||
t = "n.id desc"
|
t = "n.id desc"
|
||||||
elif o == DYN_DUEPRIORITY:
|
elif o == DYN_DUEPRIORITY:
|
||||||
t = (
|
t = (
|
||||||
"(case when queue=2 and due <= %d then (ivl / cast(%d-due+0.001 as real)) else 100000+due end)"
|
f"(case when queue={QUEUE_TYPE_REV} and due <= %d then (ivl / cast(%d-due+0.001 as real)) else 100000+due end)"
|
||||||
% (self.today, self.today)
|
% (self.today, self.today)
|
||||||
)
|
)
|
||||||
else: # DYN_DUE or unknown
|
else: # DYN_DUE or unknown
|
||||||
|
@ -1231,7 +1228,7 @@ due = (case when odue>0 then odue else due end), odue = 0, odid = 0, usn = ? whe
|
||||||
|
|
||||||
queue = ""
|
queue = ""
|
||||||
if not deck["resched"]:
|
if not deck["resched"]:
|
||||||
queue = ",queue=2"
|
queue = f",queue={QUEUE_TYPE_REV}"
|
||||||
|
|
||||||
query = (
|
query = (
|
||||||
"""
|
"""
|
||||||
|
@ -1260,9 +1257,9 @@ where id = ?
|
||||||
|
|
||||||
# learning and relearning cards may be seconds-based or day-based;
|
# learning and relearning cards may be seconds-based or day-based;
|
||||||
# other types map directly to queues
|
# other types map directly to queues
|
||||||
if card.type in (1, CARD_TYPE_RELEARNING):
|
if card.type in (CARD_TYPE_LRN, CARD_TYPE_RELEARNING):
|
||||||
if card.odue > 1000000000:
|
if card.odue > 1000000000:
|
||||||
card.queue = 1
|
card.queue = QUEUE_TYPE_LRN
|
||||||
else:
|
else:
|
||||||
card.queue = QUEUE_TYPE_DAY_LEARN_RELEARN
|
card.queue = QUEUE_TYPE_DAY_LEARN_RELEARN
|
||||||
else:
|
else:
|
||||||
|
@ -1284,8 +1281,8 @@ where id = ?
|
||||||
f.flush()
|
f.flush()
|
||||||
# handle
|
# handle
|
||||||
a = conf["leechAction"]
|
a = conf["leechAction"]
|
||||||
if a == 0:
|
if a == LEECH_SUSPEND:
|
||||||
card.queue = -1
|
card.queue = QUEUE_TYPE_SUSPENDED
|
||||||
# notify UI
|
# notify UI
|
||||||
hooks.card_did_leech(card)
|
hooks.card_did_leech(card)
|
||||||
return True
|
return True
|
||||||
|
@ -1509,7 +1506,7 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
"True if there are any rev cards due."
|
"True if there are any rev cards due."
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
(
|
(
|
||||||
"select 1 from cards where did in %s and queue = 2 "
|
f"select 1 from cards where did in %s and queue = {QUEUE_TYPE_REV} "
|
||||||
"and due <= ? limit 1"
|
"and due <= ? limit 1"
|
||||||
)
|
)
|
||||||
% self._deckLimit(),
|
% self._deckLimit(),
|
||||||
|
@ -1519,7 +1516,10 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
def newDue(self) -> Any:
|
def newDue(self) -> Any:
|
||||||
"True if there are any new cards due."
|
"True if there are any new cards due."
|
||||||
return self.col.db.scalar(
|
return self.col.db.scalar(
|
||||||
("select 1 from cards where did in %s and queue = 0 " "limit 1")
|
(
|
||||||
|
f"select 1 from cards where did in %s and queue = {QUEUE_TYPE_NEW} "
|
||||||
|
"limit 1"
|
||||||
|
)
|
||||||
% self._deckLimit()
|
% self._deckLimit()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1557,14 +1557,14 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
"Return the next interval for CARD, in seconds."
|
"Return the next interval for CARD, in seconds."
|
||||||
# preview mode?
|
# preview mode?
|
||||||
if self._previewingCard(card):
|
if self._previewingCard(card):
|
||||||
if ease == 1:
|
if ease == BUTTON_ONE:
|
||||||
return self._previewDelay(card)
|
return self._previewDelay(card)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# (re)learning?
|
# (re)learning?
|
||||||
if card.queue in (0, 1, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
if card.queue in (QUEUE_TYPE_NEW, QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
||||||
return self._nextLrnIvl(card, ease)
|
return self._nextLrnIvl(card, ease)
|
||||||
elif ease == 1:
|
elif ease == BUTTON_ONE:
|
||||||
# lapse
|
# lapse
|
||||||
conf = self._lapseConf(card)
|
conf = self._lapseConf(card)
|
||||||
if conf["delays"]:
|
if conf["delays"]:
|
||||||
|
@ -1580,17 +1580,17 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
|
|
||||||
# this isn't easily extracted from the learn code
|
# this isn't easily extracted from the learn code
|
||||||
def _nextLrnIvl(self, card: Card, ease: int) -> Any:
|
def _nextLrnIvl(self, card: Card, ease: int) -> Any:
|
||||||
if card.queue == 0:
|
if card.queue == QUEUE_TYPE_NEW:
|
||||||
card.left = self._startingLeft(card)
|
card.left = self._startingLeft(card)
|
||||||
conf = self._lrnConf(card)
|
conf = self._lrnConf(card)
|
||||||
if ease == 1:
|
if ease == BUTTON_ONE:
|
||||||
# fail
|
# fail
|
||||||
return self._delayForGrade(conf, len(conf["delays"]))
|
return self._delayForGrade(conf, len(conf["delays"]))
|
||||||
elif ease == 2:
|
elif ease == BUTTON_TWO:
|
||||||
return self._delayForRepeatingGrade(conf, card.left)
|
return self._delayForRepeatingGrade(conf, card.left)
|
||||||
elif ease == 4:
|
elif ease == BUTTON_FOUR:
|
||||||
return self._graduatingIvl(card, conf, True, fuzz=False) * 86400
|
return self._graduatingIvl(card, conf, True, fuzz=False) * 86400
|
||||||
else: # ease == 3
|
else: # ease == BUTTON_THREE
|
||||||
left = card.left % 1000 - 1
|
left = card.left % 1000 - 1
|
||||||
if left <= 0:
|
if left <= 0:
|
||||||
# graduate
|
# graduate
|
||||||
|
@ -1604,7 +1604,7 @@ To study outside of the normal schedule, click the Custom Study button below."""
|
||||||
# learning and relearning cards may be seconds-based or day-based;
|
# learning and relearning cards may be seconds-based or day-based;
|
||||||
# other types map directly to queues
|
# other types map directly to queues
|
||||||
_restoreQueueSnippet = f"""
|
_restoreQueueSnippet = f"""
|
||||||
queue = (case when type in (1,{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 1 else
|
||||||
{QUEUE_TYPE_DAY_LEARN_RELEARN} end)
|
{QUEUE_TYPE_DAY_LEARN_RELEARN} end)
|
||||||
else
|
else
|
||||||
|
@ -1616,7 +1616,8 @@ end)
|
||||||
"Suspend cards."
|
"Suspend cards."
|
||||||
self.col.log(ids)
|
self.col.log(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set queue=-1,mod=?,usn=? where id in " + ids2str(ids),
|
f"update cards set queue={QUEUE_TYPE_SUSPENDED},mod=?,usn=? where id in "
|
||||||
|
+ ids2str(ids),
|
||||||
intTime(),
|
intTime(),
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
)
|
)
|
||||||
|
@ -1625,7 +1626,9 @@ end)
|
||||||
"Unsuspend cards."
|
"Unsuspend cards."
|
||||||
self.col.log(ids)
|
self.col.log(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
("update cards set %s,mod=?,usn=? " "where queue = -1 and id in %s")
|
(
|
||||||
|
f"update cards set %s,mod=?,usn=? where queue = {QUEUE_TYPE_SUSPENDED} and id in %s"
|
||||||
|
)
|
||||||
% (self._restoreQueueSnippet, ids2str(ids)),
|
% (self._restoreQueueSnippet, ids2str(ids)),
|
||||||
intTime(),
|
intTime(),
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
|
@ -1646,7 +1649,7 @@ update cards set queue=?,mod=?,usn=? where id in """
|
||||||
def buryNote(self, nid) -> None:
|
def buryNote(self, nid) -> None:
|
||||||
"Bury all cards for note until next session."
|
"Bury all cards for note until next session."
|
||||||
cids = self.col.db.list(
|
cids = self.col.db.list(
|
||||||
"select id from cards where nid = ? and queue >= 0", nid
|
f"select id from cards where nid = ? and queue >= {QUEUE_TYPE_NEW}", nid
|
||||||
)
|
)
|
||||||
self.buryCards(cids)
|
self.buryCards(cids)
|
||||||
|
|
||||||
|
@ -1654,11 +1657,11 @@ update cards set queue=?,mod=?,usn=? where id in """
|
||||||
"Unbury all buried cards in all decks."
|
"Unbury all buried cards in all decks."
|
||||||
self.col.log(
|
self.col.log(
|
||||||
self.col.db.list(
|
self.col.db.list(
|
||||||
f"select id from cards where queue in (-2, {QUEUE_TYPE_MANUALLY_BURIED})"
|
f"select id from cards where queue in ({QUEUE_TYPE_SIBLING_BURIED}, {QUEUE_TYPE_MANUALLY_BURIED})"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
f"update cards set %s where queue in (-2, {QUEUE_TYPE_MANUALLY_BURIED})"
|
f"update cards set %s where queue in ({QUEUE_TYPE_SIBLING_BURIED}, {QUEUE_TYPE_MANUALLY_BURIED})"
|
||||||
% self._restoreQueueSnippet
|
% self._restoreQueueSnippet
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1698,14 +1701,14 @@ update cards set queue=?,mod=?,usn=? where id in """
|
||||||
buryRev = rconf.get("bury", True)
|
buryRev = rconf.get("bury", True)
|
||||||
# loop through and remove from queues
|
# loop through and remove from queues
|
||||||
for cid, queue in self.col.db.execute(
|
for cid, queue in self.col.db.execute(
|
||||||
"""
|
f"""
|
||||||
select id, queue from cards where nid=? and id!=?
|
select id, queue from cards where nid=? and id!=?
|
||||||
and (queue=0 or (queue=2 and due<=?))""",
|
and (queue={QUEUE_TYPE_NEW} or (queue={QUEUE_TYPE_REV} and due<=?))""",
|
||||||
card.nid,
|
card.nid,
|
||||||
card.id,
|
card.id,
|
||||||
self.today,
|
self.today,
|
||||||
):
|
):
|
||||||
if queue == 2:
|
if queue == QUEUE_TYPE_REV:
|
||||||
if buryRev:
|
if buryRev:
|
||||||
toBury.append(cid)
|
toBury.append(cid)
|
||||||
# if bury disabled, we still discard to give same-day spacing
|
# if bury disabled, we still discard to give same-day spacing
|
||||||
|
@ -1732,11 +1735,14 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
"Put cards at the end of the new queue."
|
"Put cards at the end of the new queue."
|
||||||
self.remFromDyn(ids)
|
self.remFromDyn(ids)
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set type=0,queue=0,ivl=0,due=0,odue=0,factor=?"
|
f"update cards set type={CARD_TYPE_NEW},queue={QUEUE_TYPE_NEW},ivl=0,due=0,odue=0,factor=?"
|
||||||
" where id in " + ids2str(ids),
|
" where id in " + ids2str(ids),
|
||||||
STARTING_FACTOR,
|
STARTING_FACTOR,
|
||||||
)
|
)
|
||||||
pmax = self.col.db.scalar("select max(due) from cards where type=0") or 0
|
pmax = (
|
||||||
|
self.col.db.scalar(f"select max(due) from cards where type={CARD_TYPE_NEW}")
|
||||||
|
or 0
|
||||||
|
)
|
||||||
# takes care of mod + usn
|
# takes care of mod + usn
|
||||||
self.sortCards(ids, start=pmax + 1)
|
self.sortCards(ids, start=pmax + 1)
|
||||||
self.col.log(ids)
|
self.col.log(ids)
|
||||||
|
@ -1760,8 +1766,8 @@ and (queue=0 or (queue=2 and due<=?))""",
|
||||||
)
|
)
|
||||||
self.remFromDyn(ids)
|
self.remFromDyn(ids)
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
"""
|
f"""
|
||||||
update cards set type=2,queue=2,ivl=:ivl,due=:due,odue=0,
|
update cards set type={CARD_TYPE_REV},queue={QUEUE_TYPE_REV},ivl=:ivl,due=:due,odue=0,
|
||||||
usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
||||||
d,
|
d,
|
||||||
)
|
)
|
||||||
|
@ -1772,11 +1778,12 @@ usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
||||||
sids = ids2str(ids)
|
sids = ids2str(ids)
|
||||||
# we want to avoid resetting due number of existing new cards on export
|
# we want to avoid resetting due number of existing new cards on export
|
||||||
nonNew = self.col.db.list(
|
nonNew = self.col.db.list(
|
||||||
"select id from cards where id in %s and (queue != 0 or type != 0)" % sids
|
f"select id from cards where id in %s and (queue != {QUEUE_TYPE_NEW} or type != {CARD_TYPE_NEW})"
|
||||||
|
% sids
|
||||||
)
|
)
|
||||||
# reset all cards
|
# reset all cards
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"update cards set reps=0,lapses=0,odid=0,odue=0,queue=0"
|
f"update cards set reps=0,lapses=0,odid=0,odue=0,queue={QUEUE_TYPE_NEW}"
|
||||||
" where id in %s" % sids
|
" where id in %s" % sids
|
||||||
)
|
)
|
||||||
# and forget any non-new cards, changing their due numbers
|
# and forget any non-new cards, changing their due numbers
|
||||||
|
@ -1817,16 +1824,16 @@ usn=:usn,mod=:mod,factor=:fact where id=:id""",
|
||||||
# shift?
|
# shift?
|
||||||
if shift:
|
if shift:
|
||||||
low = self.col.db.scalar(
|
low = self.col.db.scalar(
|
||||||
"select min(due) from cards where due >= ? and type = 0 "
|
f"select min(due) from cards where due >= ? and type = {CARD_TYPE_NEW} "
|
||||||
"and id not in %s" % scids,
|
"and id not in %s" % scids,
|
||||||
start,
|
start,
|
||||||
)
|
)
|
||||||
if low is not None:
|
if low is not None:
|
||||||
shiftby = high - low + 1
|
shiftby = high - low + 1
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
"""
|
f"""
|
||||||
update cards set mod=?, usn=?, due=due+? where id not in %s
|
update cards set mod=?, usn=?, due=due+? where id not in %s
|
||||||
and due >= ? and queue = 0"""
|
and due >= ? and queue = {QUEUE_TYPE_NEW}"""
|
||||||
% scids,
|
% scids,
|
||||||
now,
|
now,
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
|
@ -1836,7 +1843,7 @@ and due >= ? and queue = 0"""
|
||||||
# reorder cards
|
# reorder cards
|
||||||
d = []
|
d = []
|
||||||
for id, nid in self.col.db.execute(
|
for id, nid in self.col.db.execute(
|
||||||
"select id, nid from cards where type = 0 and id in " + scids
|
f"select id, nid from cards where type = {CARD_TYPE_NEW} and id in " + scids
|
||||||
):
|
):
|
||||||
d.append(dict(now=now, due=due[nid], usn=self.col.usn(), cid=id))
|
d.append(dict(now=now, due=due[nid], usn=self.col.usn(), cid=id))
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
|
@ -1874,11 +1881,11 @@ and due >= ? and queue = 0"""
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
f"""
|
f"""
|
||||||
update cards set did = odid, queue = (case
|
update cards set did = odid, queue = (case
|
||||||
when type = 1 then 0
|
when type = {CARD_TYPE_LRN} then {QUEUE_TYPE_NEW}
|
||||||
when type = {CARD_TYPE_RELEARNING} then 2
|
when type = {CARD_TYPE_RELEARNING} then {QUEUE_TYPE_REV}
|
||||||
else type end), type = (case
|
else type end), type = (case
|
||||||
when type = 1 then 0
|
when type = {CARD_TYPE_LRN} then {CARD_TYPE_NEW}
|
||||||
when type = {CARD_TYPE_RELEARNING} then 2
|
when type = {CARD_TYPE_RELEARNING} then {CARD_TYPE_REV}
|
||||||
else type end),
|
else type end),
|
||||||
due = odue, odue = 0, odid = 0, usn = ? where odid != 0""",
|
due = odue, odue = 0, odid = 0, usn = ? where odid != 0""",
|
||||||
self.col.usn(),
|
self.col.usn(),
|
||||||
|
@ -1890,8 +1897,8 @@ due = odue, odue = 0, odid = 0, usn = ? where odid != 0""",
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
f"""
|
f"""
|
||||||
update cards set
|
update cards set
|
||||||
due = odue, queue = 2, type = 2, mod = %d, usn = %d, odue = 0
|
due = odue, queue = {QUEUE_TYPE_REV}, type = {CARD_TYPE_REV}, mod = %d, usn = %d, odue = 0
|
||||||
where queue in (1,{QUEUE_TYPE_DAY_LEARN_RELEARN}) and type in (2, {CARD_TYPE_RELEARNING})
|
where queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_DAY_LEARN_RELEARN}) and type in ({CARD_TYPE_REV}, {CARD_TYPE_RELEARNING})
|
||||||
"""
|
"""
|
||||||
% (intTime(), self.col.usn())
|
% (intTime(), self.col.usn())
|
||||||
)
|
)
|
||||||
|
@ -1899,15 +1906,15 @@ due = odue, odue = 0, odid = 0, usn = ? where odid != 0""",
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
f"""
|
f"""
|
||||||
update cards set
|
update cards set
|
||||||
due = %d+ivl, queue = 2, type = 2, mod = %d, usn = %d, odue = 0
|
due = %d+ivl, queue = {QUEUE_TYPE_REV}, type = {CARD_TYPE_REV}, mod = %d, usn = %d, odue = 0
|
||||||
where queue in (1,{QUEUE_TYPE_DAY_LEARN_RELEARN}) and type in (2, {CARD_TYPE_RELEARNING})
|
where queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_DAY_LEARN_RELEARN}) and type in ({CARD_TYPE_REV}, {CARD_TYPE_RELEARNING})
|
||||||
"""
|
"""
|
||||||
% (self.today, intTime(), self.col.usn())
|
% (self.today, intTime(), self.col.usn())
|
||||||
)
|
)
|
||||||
# remove new cards from learning
|
# remove new cards from learning
|
||||||
self.forgetCards(
|
self.forgetCards(
|
||||||
self.col.db.list(
|
self.col.db.list(
|
||||||
f"select id from cards where queue in (1,{QUEUE_TYPE_DAY_LEARN_RELEARN})"
|
f"select id from cards where queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_DAY_LEARN_RELEARN})"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1916,13 +1923,13 @@ due = odue, odue = 0, odid = 0, usn = ? where odid != 0""",
|
||||||
self.col.db.execute(
|
self.col.db.execute(
|
||||||
f"""
|
f"""
|
||||||
update cards set type = (case
|
update cards set type = (case
|
||||||
when type = 1 then 0
|
when type = {CARD_TYPE_LRN} then {CARD_TYPE_NEW}
|
||||||
when type in (2, {CARD_TYPE_RELEARNING}) then 2
|
when type in ({CARD_TYPE_REV}, {CARD_TYPE_RELEARNING}) then {CARD_TYPE_REV}
|
||||||
else type end),
|
else type end),
|
||||||
due = (case when odue then odue else due end),
|
due = (case when odue then odue else due end),
|
||||||
odue = 0,
|
odue = 0,
|
||||||
mod = %d, usn = %d
|
mod = %d, usn = %d
|
||||||
where queue < 0"""
|
where queue < {QUEUE_TYPE_NEW}"""
|
||||||
% (intTime(), self.col.usn())
|
% (intTime(), self.col.usn())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1936,7 +1943,9 @@ where queue < 0"""
|
||||||
# adding 'hard' in v2 scheduler means old ease entries need shifting
|
# adding 'hard' in v2 scheduler means old ease entries need shifting
|
||||||
# up or down
|
# up or down
|
||||||
def _remapLearningAnswers(self, sql: str) -> None:
|
def _remapLearningAnswers(self, sql: str) -> None:
|
||||||
self.col.db.execute("update revlog set %s and type in (0,2)" % sql)
|
self.col.db.execute(
|
||||||
|
f"update revlog set %s and type in ({CARD_TYPE_NEW},{CARD_TYPE_REV})" % sql
|
||||||
|
)
|
||||||
|
|
||||||
def moveToV1(self) -> None:
|
def moveToV1(self) -> None:
|
||||||
self._emptyAllFiltered()
|
self._emptyAllFiltered()
|
||||||
|
|
|
@ -6,12 +6,17 @@ import json
|
||||||
import time
|
import time
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
from anki.consts import *
|
||||||
from anki.lang import _, ngettext
|
from anki.lang import _, ngettext
|
||||||
from anki.utils import fmtTimeSpan, ids2str
|
from anki.utils import fmtTimeSpan, ids2str
|
||||||
|
|
||||||
# Card stats
|
# Card stats
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
PERIOD_MONTH = 0
|
||||||
|
PERIOD_YEAR = 1
|
||||||
|
PERIOD_LIFE = 2
|
||||||
|
|
||||||
|
|
||||||
class CardStats:
|
class CardStats:
|
||||||
def __init__(self, col, card) -> None:
|
def __init__(self, col, card) -> None:
|
||||||
|
@ -30,18 +35,18 @@ class CardStats:
|
||||||
if first:
|
if first:
|
||||||
self.addLine(_("First Review"), self.date(first / 1000))
|
self.addLine(_("First Review"), self.date(first / 1000))
|
||||||
self.addLine(_("Latest Review"), self.date(last / 1000))
|
self.addLine(_("Latest Review"), self.date(last / 1000))
|
||||||
if c.type in (1, 2):
|
if c.type in (CARD_TYPE_LRN, CARD_TYPE_REV):
|
||||||
if c.odid or c.queue < 0:
|
if c.odid or c.queue < QUEUE_TYPE_NEW:
|
||||||
next = None
|
next = None
|
||||||
else:
|
else:
|
||||||
if c.queue in (2, 3):
|
if c.queue in (QUEUE_TYPE_REV, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
||||||
next = time.time() + ((c.due - self.col.sched.today) * 86400)
|
next = time.time() + ((c.due - self.col.sched.today) * 86400)
|
||||||
else:
|
else:
|
||||||
next = c.due
|
next = c.due
|
||||||
next = self.date(next)
|
next = self.date(next)
|
||||||
if next:
|
if next:
|
||||||
self.addLine(_("Due"), next)
|
self.addLine(_("Due"), next)
|
||||||
if c.queue == 2:
|
if c.queue == QUEUE_TYPE_REV:
|
||||||
self.addLine(_("Interval"), fmt(c.ivl * 86400))
|
self.addLine(_("Interval"), fmt(c.ivl * 86400))
|
||||||
self.addLine(_("Ease"), "%d%%" % (c.factor / 10.0))
|
self.addLine(_("Ease"), "%d%%" % (c.factor / 10.0))
|
||||||
self.addLine(_("Reviews"), "%d" % c.reps)
|
self.addLine(_("Reviews"), "%d" % c.reps)
|
||||||
|
@ -52,7 +57,7 @@ class CardStats:
|
||||||
if cnt:
|
if cnt:
|
||||||
self.addLine(_("Average Time"), self.time(total / float(cnt)))
|
self.addLine(_("Average Time"), self.time(total / float(cnt)))
|
||||||
self.addLine(_("Total Time"), self.time(total))
|
self.addLine(_("Total Time"), self.time(total))
|
||||||
elif c.queue == 0:
|
elif c.queue == QUEUE_TYPE_NEW:
|
||||||
self.addLine(_("Position"), c.due)
|
self.addLine(_("Position"), c.due)
|
||||||
self.addLine(_("Card Type"), c.template()["name"])
|
self.addLine(_("Card Type"), c.template()["name"])
|
||||||
self.addLine(_("Note Type"), c.model()["name"])
|
self.addLine(_("Note Type"), c.model()["name"])
|
||||||
|
@ -102,14 +107,14 @@ class CollectionStats:
|
||||||
def __init__(self, col) -> None:
|
def __init__(self, col) -> None:
|
||||||
self.col = col
|
self.col = col
|
||||||
self._stats = None
|
self._stats = None
|
||||||
self.type = 0
|
self.type = PERIOD_MONTH
|
||||||
self.width = 600
|
self.width = 600
|
||||||
self.height = 200
|
self.height = 200
|
||||||
self.wholeCollection = False
|
self.wholeCollection = False
|
||||||
|
|
||||||
# assumes jquery & plot are available in document
|
# assumes jquery & plot are available in document
|
||||||
def report(self, type=0) -> str:
|
def report(self, type=PERIOD_MONTH) -> str:
|
||||||
# 0=days, 1=weeks, 2=months
|
# 0=month, 1=year, 2=deck life
|
||||||
self.type = type
|
self.type = type
|
||||||
from .statsbg import bg
|
from .statsbg import bg
|
||||||
|
|
||||||
|
@ -149,13 +154,13 @@ body {background-image: url(data:image/png;base64,%s); }
|
||||||
if lim:
|
if lim:
|
||||||
lim = " and " + lim
|
lim = " and " + lim
|
||||||
cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first(
|
cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first(
|
||||||
"""
|
f"""
|
||||||
select count(), sum(time)/1000,
|
select count(), sum(time)/1000,
|
||||||
sum(case when ease = 1 then 1 else 0 end), /* failed */
|
sum(case when ease = 1 then 1 else 0 end), /* failed */
|
||||||
sum(case when type = 0 then 1 else 0 end), /* learning */
|
sum(case when type = {REVLOG_LRN} then 1 else 0 end), /* learning */
|
||||||
sum(case when type = 1 then 1 else 0 end), /* review */
|
sum(case when type = {REVLOG_REV} then 1 else 0 end), /* review */
|
||||||
sum(case when type = 2 then 1 else 0 end), /* relearn */
|
sum(case when type = {REVLOG_RELRN} then 1 else 0 end), /* relearn */
|
||||||
sum(case when type = 3 then 1 else 0 end) /* filter */
|
sum(case when type = {REVLOG_CRAM} then 1 else 0 end) /* filter */
|
||||||
from revlog where id > ? """
|
from revlog where id > ? """
|
||||||
+ lim,
|
+ lim,
|
||||||
(self.col.sched.dayCutoff - 86400) * 1000,
|
(self.col.sched.dayCutoff - 86400) * 1000,
|
||||||
|
@ -215,9 +220,9 @@ from revlog where id > ? """
|
||||||
|
|
||||||
def get_start_end_chunk(self, by="review") -> Tuple[int, Optional[int], int]:
|
def get_start_end_chunk(self, by="review") -> Tuple[int, Optional[int], int]:
|
||||||
start = 0
|
start = 0
|
||||||
if self.type == 0:
|
if self.type == PERIOD_MONTH:
|
||||||
end, chunk = 31, 1
|
end, chunk = 31, 1
|
||||||
elif self.type == 1:
|
elif self.type == PERIOD_YEAR:
|
||||||
end, chunk = 52, 7
|
end, chunk = 52, 7
|
||||||
else: # self.type == 2:
|
else: # self.type == 2:
|
||||||
end = None
|
end = None
|
||||||
|
@ -279,8 +284,8 @@ from revlog where id > ? """
|
||||||
self._line(i, _("Total"), ngettext("%d review", "%d reviews", tot) % tot)
|
self._line(i, _("Total"), ngettext("%d review", "%d reviews", tot) % tot)
|
||||||
self._line(i, _("Average"), self._avgDay(tot, num, _("reviews")))
|
self._line(i, _("Average"), self._avgDay(tot, num, _("reviews")))
|
||||||
tomorrow = self.col.db.scalar(
|
tomorrow = self.col.db.scalar(
|
||||||
"""
|
f"""
|
||||||
select count() from cards where did in %s and queue in (2,3)
|
select count() from cards where did in %s and queue in ({QUEUE_TYPE_REV},{QUEUE_TYPE_DAY_LEARN_RELEARN})
|
||||||
and due = ?"""
|
and due = ?"""
|
||||||
% self._limit(),
|
% self._limit(),
|
||||||
self.col.sched.today + 1,
|
self.col.sched.today + 1,
|
||||||
|
@ -296,12 +301,12 @@ and due = ?"""
|
||||||
if end is not None:
|
if end is not None:
|
||||||
lim += " and day < %d" % end
|
lim += " and day < %d" % end
|
||||||
return self.col.db.all(
|
return self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select (due-:today)/:chunk as day,
|
select (due-:today)/:chunk as day,
|
||||||
sum(case when ivl < 21 then 1 else 0 end), -- yng
|
sum(case when ivl < 21 then 1 else 0 end), -- yng
|
||||||
sum(case when ivl >= 21 then 1 else 0 end) -- mtr
|
sum(case when ivl >= 21 then 1 else 0 end) -- mtr
|
||||||
from cards
|
from cards
|
||||||
where did in %s and queue in (2,3)
|
where did in %s and queue in ({QUEUE_TYPE_REV},{QUEUE_TYPE_DAY_LEARN_RELEARN})
|
||||||
%s
|
%s
|
||||||
group by day order by day"""
|
group by day order by day"""
|
||||||
% (self._limit(), lim),
|
% (self._limit(), lim),
|
||||||
|
@ -396,7 +401,7 @@ group by day order by day"""
|
||||||
(10, colCram, _("Cram")),
|
(10, colCram, _("Cram")),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if self.type == 0:
|
if self.type == PERIOD_MONTH:
|
||||||
t = _("Minutes")
|
t = _("Minutes")
|
||||||
convHours = False
|
convHours = False
|
||||||
else:
|
else:
|
||||||
|
@ -513,7 +518,7 @@ group by day order by day"""
|
||||||
lim = "where " + " and ".join(lims)
|
lim = "where " + " and ".join(lims)
|
||||||
else:
|
else:
|
||||||
lim = ""
|
lim = ""
|
||||||
if self.type == 0:
|
if self.type == PERIOD_MONTH:
|
||||||
tf = 60.0 # minutes
|
tf = 60.0 # minutes
|
||||||
else:
|
else:
|
||||||
tf = 3600.0 # hours
|
tf = 3600.0 # hours
|
||||||
|
@ -543,25 +548,25 @@ group by day order by day"""
|
||||||
lim = "where " + " and ".join(lims)
|
lim = "where " + " and ".join(lims)
|
||||||
else:
|
else:
|
||||||
lim = ""
|
lim = ""
|
||||||
if self.type == 0:
|
if self.type == PERIOD_MONTH:
|
||||||
tf = 60.0 # minutes
|
tf = 60.0 # minutes
|
||||||
else:
|
else:
|
||||||
tf = 3600.0 # hours
|
tf = 3600.0 # hours
|
||||||
return self.col.db.all(
|
return self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select
|
select
|
||||||
(cast((id/1000.0 - :cut) / 86400.0 as int))/:chunk as day,
|
(cast((id/1000.0 - :cut) / 86400.0 as int))/:chunk as day,
|
||||||
sum(case when type = 0 then 1 else 0 end), -- lrn count
|
sum(case when type = {REVLOG_LRN} then 1 else 0 end), -- lrn count
|
||||||
sum(case when type = 1 and lastIvl < 21 then 1 else 0 end), -- yng count
|
sum(case when type = {REVLOG_REV} and lastIvl < 21 then 1 else 0 end), -- yng count
|
||||||
sum(case when type = 1 and lastIvl >= 21 then 1 else 0 end), -- mtr count
|
sum(case when type = {REVLOG_REV} and lastIvl >= 21 then 1 else 0 end), -- mtr count
|
||||||
sum(case when type = 2 then 1 else 0 end), -- lapse count
|
sum(case when type = {REVLOG_RELRN} then 1 else 0 end), -- lapse count
|
||||||
sum(case when type = 3 then 1 else 0 end), -- cram count
|
sum(case when type = {REVLOG_CRAM} then 1 else 0 end), -- cram count
|
||||||
sum(case when type = 0 then time/1000.0 else 0 end)/:tf, -- lrn time
|
sum(case when type = {REVLOG_LRN} then time/1000.0 else 0 end)/:tf, -- lrn time
|
||||||
-- yng + mtr time
|
-- yng + mtr time
|
||||||
sum(case when type = 1 and lastIvl < 21 then time/1000.0 else 0 end)/:tf,
|
sum(case when type = {REVLOG_REV} and lastIvl < 21 then time/1000.0 else 0 end)/:tf,
|
||||||
sum(case when type = 1 and lastIvl >= 21 then time/1000.0 else 0 end)/:tf,
|
sum(case when type = {REVLOG_REV} and lastIvl >= 21 then time/1000.0 else 0 end)/:tf,
|
||||||
sum(case when type = 2 then time/1000.0 else 0 end)/:tf, -- lapse time
|
sum(case when type = {REVLOG_RELRN} then time/1000.0 else 0 end)/:tf, -- lapse time
|
||||||
sum(case when type = 3 then time/1000.0 else 0 end)/:tf -- cram time
|
sum(case when type = {REVLOG_CRAM} then time/1000.0 else 0 end)/:tf -- cram time
|
||||||
from revlog %s
|
from revlog %s
|
||||||
group by day order by day"""
|
group by day order by day"""
|
||||||
% lim,
|
% lim,
|
||||||
|
@ -606,9 +611,9 @@ group by day order by day)"""
|
||||||
for (grp, cnt) in ivls:
|
for (grp, cnt) in ivls:
|
||||||
tot += cnt
|
tot += cnt
|
||||||
totd.append((grp, tot / float(all) * 100))
|
totd.append((grp, tot / float(all) * 100))
|
||||||
if self.type == 0:
|
if self.type == PERIOD_MONTH:
|
||||||
ivlmax = 31
|
ivlmax = 31
|
||||||
elif self.type == 1:
|
elif self.type == PERIOD_YEAR:
|
||||||
ivlmax = 52
|
ivlmax = 52
|
||||||
else:
|
else:
|
||||||
ivlmax = max(5, ivls[-1][0])
|
ivlmax = max(5, ivls[-1][0])
|
||||||
|
@ -643,9 +648,9 @@ group by day order by day)"""
|
||||||
lim = "and grp <= %d" % end if end else ""
|
lim = "and grp <= %d" % end if end else ""
|
||||||
data = [
|
data = [
|
||||||
self.col.db.all(
|
self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select ivl / :chunk as grp, count() from cards
|
select ivl / :chunk as grp, count() from cards
|
||||||
where did in %s and queue = 2 %s
|
where did in %s and queue = {QUEUE_TYPE_REV} %s
|
||||||
group by grp
|
group by grp
|
||||||
order by grp"""
|
order by grp"""
|
||||||
% (self._limit(), lim),
|
% (self._limit(), lim),
|
||||||
|
@ -656,8 +661,8 @@ order by grp"""
|
||||||
data
|
data
|
||||||
+ list(
|
+ list(
|
||||||
self.col.db.first(
|
self.col.db.first(
|
||||||
"""
|
f"""
|
||||||
select count(), avg(ivl), max(ivl) from cards where did in %s and queue = 2"""
|
select count(), avg(ivl), max(ivl) from cards where did in %s and queue = {QUEUE_TYPE_REV}"""
|
||||||
% self._limit()
|
% self._limit()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -675,9 +680,9 @@ select count(), avg(ivl), max(ivl) from cards where did in %s and queue = 2"""
|
||||||
types = ("lrn", "yng", "mtr")
|
types = ("lrn", "yng", "mtr")
|
||||||
eases = self._eases()
|
eases = self._eases()
|
||||||
for (type, ease, cnt) in eases:
|
for (type, ease, cnt) in eases:
|
||||||
if type == 1:
|
if type == CARD_TYPE_LRN:
|
||||||
ease += 5
|
ease += 5
|
||||||
elif type == 2:
|
elif type == CARD_TYPE_REV:
|
||||||
ease += 10
|
ease += 10
|
||||||
n = types[type]
|
n = types[type]
|
||||||
d[n].append((ease, cnt))
|
d[n].append((ease, cnt))
|
||||||
|
@ -714,7 +719,7 @@ select count(), avg(ivl), max(ivl) from cards where did in %s and queue = 2"""
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
def _easeInfo(self, eases) -> str:
|
def _easeInfo(self, eases) -> str:
|
||||||
types = {0: [0, 0], 1: [0, 0], 2: [0, 0]}
|
types = {PERIOD_MONTH: [0, 0], PERIOD_YEAR: [0, 0], PERIOD_LIFE: [0, 0]}
|
||||||
for (type, ease, cnt) in eases:
|
for (type, ease, cnt) in eases:
|
||||||
if ease == 1:
|
if ease == 1:
|
||||||
types[type][0] += cnt
|
types[type][0] += cnt
|
||||||
|
@ -759,12 +764,12 @@ select count(), avg(ivl), max(ivl) from cards where did in %s and queue = 2"""
|
||||||
else:
|
else:
|
||||||
ease4repl = "ease"
|
ease4repl = "ease"
|
||||||
return self.col.db.all(
|
return self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select (case
|
select (case
|
||||||
when type in (0,2) then 0
|
when type in ({REVLOG_LRN},{REVLOG_RELRN}) then 0
|
||||||
when lastIvl < 21 then 1
|
when lastIvl < 21 then 1
|
||||||
else 2 end) as thetype,
|
else 2 end) as thetype,
|
||||||
(case when type in (0,2) and ease = 4 then %s else ease end), count() from revlog %s
|
(case when type in ({REVLOG_LRN},{REVLOG_RELRN}) and ease = 4 then %s else ease end), count() from revlog %s
|
||||||
group by thetype, ease
|
group by thetype, ease
|
||||||
order by thetype, ease"""
|
order by thetype, ease"""
|
||||||
% (ease4repl, lim)
|
% (ease4repl, lim)
|
||||||
|
@ -853,13 +858,13 @@ order by thetype, ease"""
|
||||||
if pd:
|
if pd:
|
||||||
lim += " and id > %d" % ((self.col.sched.dayCutoff - (86400 * pd)) * 1000)
|
lim += " and id > %d" % ((self.col.sched.dayCutoff - (86400 * pd)) * 1000)
|
||||||
return self.col.db.all(
|
return self.col.db.all(
|
||||||
"""
|
f"""
|
||||||
select
|
select
|
||||||
23 - ((cast((:cut - id/1000) / 3600.0 as int)) %% 24) as hour,
|
23 - ((cast((:cut - id/1000) / 3600.0 as int)) %% 24) as hour,
|
||||||
sum(case when ease = 1 then 0 else 1 end) /
|
sum(case when ease = 1 then 0 else 1 end) /
|
||||||
cast(count() as float) * 100,
|
cast(count() as float) * 100,
|
||||||
count()
|
count()
|
||||||
from revlog where type in (0,1,2) %s
|
from revlog where type in ({REVLOG_LRN},{REVLOG_REV},{REVLOG_RELRN}) %s
|
||||||
group by hour having count() > 30 order by hour"""
|
group by hour having count() > 30 order by hour"""
|
||||||
% lim,
|
% lim,
|
||||||
cut=self.col.sched.dayCutoff - (rolloverHour * 3600),
|
cut=self.col.sched.dayCutoff - (rolloverHour * 3600),
|
||||||
|
@ -929,23 +934,23 @@ when you answer "good" on a review."""
|
||||||
|
|
||||||
def _factors(self) -> Any:
|
def _factors(self) -> Any:
|
||||||
return self.col.db.first(
|
return self.col.db.first(
|
||||||
"""
|
f"""
|
||||||
select
|
select
|
||||||
min(factor) / 10.0,
|
min(factor) / 10.0,
|
||||||
avg(factor) / 10.0,
|
avg(factor) / 10.0,
|
||||||
max(factor) / 10.0
|
max(factor) / 10.0
|
||||||
from cards where did in %s and queue = 2"""
|
from cards where did in %s and queue = {QUEUE_TYPE_REV}"""
|
||||||
% self._limit()
|
% self._limit()
|
||||||
)
|
)
|
||||||
|
|
||||||
def _cards(self) -> Any:
|
def _cards(self) -> Any:
|
||||||
return self.col.db.first(
|
return self.col.db.first(
|
||||||
"""
|
f"""
|
||||||
select
|
select
|
||||||
sum(case when queue=2 and ivl >= 21 then 1 else 0 end), -- mtr
|
sum(case when queue={QUEUE_TYPE_REV} and ivl >= 21 then 1 else 0 end), -- mtr
|
||||||
sum(case when queue in (1,3) or (queue=2 and ivl < 21) then 1 else 0 end), -- yng/lrn
|
sum(case when queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_DAY_LEARN_RELEARN}) or (queue={QUEUE_TYPE_REV} and ivl < 21) then 1 else 0 end), -- yng/lrn
|
||||||
sum(case when queue=0 then 1 else 0 end), -- new
|
sum(case when queue={QUEUE_TYPE_NEW} then 1 else 0 end), -- new
|
||||||
sum(case when queue<0 then 1 else 0 end) -- susp
|
sum(case when queue<{QUEUE_TYPE_NEW} then 1 else 0 end) -- susp
|
||||||
from cards where did in %s"""
|
from cards where did in %s"""
|
||||||
% self._limit()
|
% self._limit()
|
||||||
)
|
)
|
||||||
|
|
|
@ -111,7 +111,7 @@ def _upgrade(col, ver) -> None:
|
||||||
if ver < 3:
|
if ver < 3:
|
||||||
# new deck properties
|
# new deck properties
|
||||||
for d in col.decks.all():
|
for d in col.decks.all():
|
||||||
d["dyn"] = 0
|
d["dyn"] = DECK_STD
|
||||||
d["collapsed"] = False
|
d["collapsed"] = False
|
||||||
col.decks.save(d)
|
col.decks.save(d)
|
||||||
if ver < 4:
|
if ver < 4:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from anki.consts import *
|
||||||
from anki.find import Finder
|
from anki.find import Finder
|
||||||
from tests.shared import getEmptyCol
|
from tests.shared import getEmptyCol
|
||||||
|
|
||||||
|
@ -91,13 +92,13 @@ def test_findCards():
|
||||||
assert len(deck.findCards('"goats are"')) == 1
|
assert len(deck.findCards('"goats are"')) == 1
|
||||||
# card states
|
# card states
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.queue = c.type = 2
|
c.queue = c.type = CARD_TYPE_REV
|
||||||
assert deck.findCards("is:review") == []
|
assert deck.findCards("is:review") == []
|
||||||
c.flush()
|
c.flush()
|
||||||
assert deck.findCards("is:review") == [c.id]
|
assert deck.findCards("is:review") == [c.id]
|
||||||
assert deck.findCards("is:due") == []
|
assert deck.findCards("is:due") == []
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.flush()
|
c.flush()
|
||||||
assert deck.findCards("is:due") == [c.id]
|
assert deck.findCards("is:due") == [c.id]
|
||||||
assert len(deck.findCards("-is:due")) == 4
|
assert len(deck.findCards("-is:due")) == 4
|
||||||
|
|
|
@ -4,7 +4,7 @@ import copy
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.consts import STARTING_FACTOR
|
from anki.consts import *
|
||||||
from anki.utils import intTime
|
from anki.utils import intTime
|
||||||
from tests.shared import getEmptyCol as getEmptyColOrig
|
from tests.shared import getEmptyCol as getEmptyColOrig
|
||||||
|
|
||||||
|
@ -46,13 +46,13 @@ def test_new():
|
||||||
# fetch it
|
# fetch it
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
assert c
|
assert c
|
||||||
assert c.queue == 0
|
assert c.queue == QUEUE_TYPE_NEW
|
||||||
assert c.type == 0
|
assert c.type == CARD_TYPE_NEW
|
||||||
# if we answer it, it should become a learn card
|
# if we answer it, it should become a learn card
|
||||||
t = intTime()
|
t = intTime()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 1
|
assert c.type == CARD_TYPE_LRN
|
||||||
assert c.due >= t
|
assert c.due >= t
|
||||||
|
|
||||||
# disabled for now, as the learn fudging makes this randomly fail
|
# disabled for now, as the learn fudging makes this randomly fail
|
||||||
|
@ -163,11 +163,11 @@ def test_learn():
|
||||||
assert c.left % 1000 == 1
|
assert c.left % 1000 == 1
|
||||||
assert c.left // 1000 == 1
|
assert c.left // 1000 == 1
|
||||||
# the next pass should graduate the card
|
# the next pass should graduate the card
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 1
|
assert c.type == CARD_TYPE_LRN
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
assert c.type == 2
|
assert c.type == CARD_TYPE_REV
|
||||||
# should be due tomorrow, with an interval of 1
|
# should be due tomorrow, with an interval of 1
|
||||||
assert c.due == d.sched.today + 1
|
assert c.due == d.sched.today + 1
|
||||||
assert c.ivl == 1
|
assert c.ivl == 1
|
||||||
|
@ -175,27 +175,27 @@ def test_learn():
|
||||||
c.type = 0
|
c.type = 0
|
||||||
c.queue = 1
|
c.queue = 1
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.type == 2
|
assert c.type == CARD_TYPE_REV
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
assert checkRevIvl(d, c, 4)
|
assert checkRevIvl(d, c, 4)
|
||||||
# revlog should have been updated each time
|
# revlog should have been updated each time
|
||||||
assert d.db.scalar("select count() from revlog where type = 0") == 5
|
assert d.db.scalar("select count() from revlog where type = 0") == 5
|
||||||
# now failed card handling
|
# now failed card handling
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 1
|
c.queue = 1
|
||||||
c.odue = 123
|
c.odue = 123
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.due == 123
|
assert c.due == 123
|
||||||
assert c.type == 2
|
assert c.type == CARD_TYPE_REV
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
# we should be able to remove manually, too
|
# we should be able to remove manually, too
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 1
|
c.queue = 1
|
||||||
c.odue = 321
|
c.odue = 321
|
||||||
c.flush()
|
c.flush()
|
||||||
d.sched.removeLrn()
|
d.sched.removeLrn()
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
assert c.due == 321
|
assert c.due == 321
|
||||||
|
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ def test_learn_day():
|
||||||
# answering it will place it in queue 3
|
# answering it will place it in queue 3
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
assert c.due == d.sched.today + 1
|
assert c.due == d.sched.today + 1
|
||||||
assert c.queue == 3
|
assert c.queue == CARD_TYPE_RELEARNING
|
||||||
assert not d.sched.getCard()
|
assert not d.sched.getCard()
|
||||||
# for testing, move it back a day
|
# for testing, move it back a day
|
||||||
c.due -= 1
|
c.due -= 1
|
||||||
|
@ -259,7 +259,7 @@ def test_learn_day():
|
||||||
assert ni(c, 2) == 86400 * 2
|
assert ni(c, 2) == 86400 * 2
|
||||||
# if we fail it, it should be back in the correct queue
|
# if we fail it, it should be back in the correct queue
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
d.undo()
|
d.undo()
|
||||||
d.reset()
|
d.reset()
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
|
@ -271,7 +271,7 @@ def test_learn_day():
|
||||||
# the last pass should graduate it into a review card
|
# the last pass should graduate it into a review card
|
||||||
assert ni(c, 2) == 86400
|
assert ni(c, 2) == 86400
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
assert c.queue == c.type == 2
|
assert c.queue == CARD_TYPE_REV and c.type == QUEUE_TYPE_REV
|
||||||
# if the lapse step is tomorrow, failing it should handle the counts
|
# if the lapse step is tomorrow, failing it should handle the counts
|
||||||
# correctly
|
# correctly
|
||||||
c.due = 0
|
c.due = 0
|
||||||
|
@ -281,7 +281,7 @@ def test_learn_day():
|
||||||
d.sched._cardConf(c)["lapse"]["delays"] = [1440]
|
d.sched._cardConf(c)["lapse"]["delays"] = [1440]
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 3
|
assert c.queue == CARD_TYPE_RELEARNING
|
||||||
assert d.sched.counts() == (0, 0, 0)
|
assert d.sched.counts() == (0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,8 +294,8 @@ def test_reviews():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# set the card up as a review card, due 8 days ago
|
# set the card up as a review card, due 8 days ago
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = d.sched.today - 8
|
c.due = d.sched.today - 8
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
c.reps = 3
|
c.reps = 3
|
||||||
|
@ -311,7 +311,7 @@ def test_reviews():
|
||||||
d.reset()
|
d.reset()
|
||||||
d.sched._cardConf(c)["lapse"]["delays"] = [2, 20]
|
d.sched._cardConf(c)["lapse"]["delays"] = [2, 20]
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
# it should be due tomorrow, with an interval of 1
|
# it should be due tomorrow, with an interval of 1
|
||||||
assert c.odue == d.sched.today + 1
|
assert c.odue == d.sched.today + 1
|
||||||
assert c.ivl == 1
|
assert c.ivl == 1
|
||||||
|
@ -333,7 +333,7 @@ def test_reviews():
|
||||||
c = copy.copy(cardcopy)
|
c = copy.copy(cardcopy)
|
||||||
c.flush()
|
c.flush()
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
# the new interval should be (100 + 8/4) * 1.2 = 122
|
# the new interval should be (100 + 8/4) * 1.2 = 122
|
||||||
assert checkRevIvl(d, c, 122)
|
assert checkRevIvl(d, c, 122)
|
||||||
assert c.due == d.sched.today + c.ivl
|
assert c.due == d.sched.today + c.ivl
|
||||||
|
@ -376,9 +376,9 @@ def test_reviews():
|
||||||
hooks.card_did_leech.append(onLeech)
|
hooks.card_did_leech.append(onLeech)
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert hooked
|
assert hooked
|
||||||
assert c.queue == -1
|
assert c.queue == QUEUE_TYPE_SUSPENDED
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == -1
|
assert c.queue == QUEUE_TYPE_SUSPENDED
|
||||||
|
|
||||||
|
|
||||||
def test_button_spacing():
|
def test_button_spacing():
|
||||||
|
@ -388,8 +388,8 @@ def test_button_spacing():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# 1 day ivl review card due now
|
# 1 day ivl review card due now
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = d.sched.today
|
c.due = d.sched.today
|
||||||
c.reps = 1
|
c.reps = 1
|
||||||
c.ivl = 1
|
c.ivl = 1
|
||||||
|
@ -412,7 +412,7 @@ def test_overdue_lapse():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# simulate a review that was lapsed and is now due for its normal review
|
# simulate a review that was lapsed and is now due for its normal review
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 1
|
c.queue = 1
|
||||||
c.due = -1
|
c.due = -1
|
||||||
c.odue = -1
|
c.odue = -1
|
||||||
|
@ -492,7 +492,7 @@ def test_nextIvl():
|
||||||
assert ni(c, 3) == 4 * 86400
|
assert ni(c, 3) == 4 * 86400
|
||||||
# lapsed cards
|
# lapsed cards
|
||||||
##################################################
|
##################################################
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
assert ni(c, 1) == 60
|
assert ni(c, 1) == 60
|
||||||
|
@ -500,7 +500,7 @@ def test_nextIvl():
|
||||||
assert ni(c, 3) == 100 * 86400
|
assert ni(c, 3) == 100 * 86400
|
||||||
# review cards
|
# review cards
|
||||||
##################################################
|
##################################################
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
# failing it should put it at 60s
|
# failing it should put it at 60s
|
||||||
|
@ -551,20 +551,20 @@ def test_suspend():
|
||||||
# should cope with rev cards being relearnt
|
# should cope with rev cards being relearnt
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.flush()
|
c.flush()
|
||||||
d.reset()
|
d.reset()
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.due >= time.time()
|
assert c.due >= time.time()
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 2
|
assert c.type == CARD_TYPE_REV
|
||||||
d.sched.suspendCards([c.id])
|
d.sched.suspendCards([c.id])
|
||||||
d.sched.unsuspendCards([c.id])
|
d.sched.unsuspendCards([c.id])
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
assert c.type == 2
|
assert c.type == CARD_TYPE_REV
|
||||||
assert c.due == 1
|
assert c.due == 1
|
||||||
# should cope with cards in cram decks
|
# should cope with cards in cram decks
|
||||||
c.due = 1
|
c.due = 1
|
||||||
|
@ -587,7 +587,8 @@ def test_cram():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.type = c.queue = 2
|
c.queue = CARD_TYPE_REV
|
||||||
|
c.type = QUEUE_TYPE_REV
|
||||||
# due in 25 days, so it's been waiting 75 days
|
# due in 25 days, so it's been waiting 75 days
|
||||||
c.due = d.sched.today + 25
|
c.due = d.sched.today + 25
|
||||||
c.mod = 1
|
c.mod = 1
|
||||||
|
@ -622,7 +623,7 @@ def test_cram():
|
||||||
# int(75*1.85) = 138
|
# int(75*1.85) = 138
|
||||||
assert c.ivl == 138
|
assert c.ivl == 138
|
||||||
assert c.odue == 138
|
assert c.odue == 138
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
# should be logged as a cram rep
|
# should be logged as a cram rep
|
||||||
assert d.db.scalar("select type from revlog order by id desc limit 1") == 3
|
assert d.db.scalar("select type from revlog order by id desc limit 1") == 3
|
||||||
# check ivls again
|
# check ivls again
|
||||||
|
@ -634,7 +635,7 @@ def test_cram():
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
assert c.ivl == 138
|
assert c.ivl == 138
|
||||||
assert c.due == 138
|
assert c.due == 138
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
# and it will have moved back to the previous deck
|
# and it will have moved back to the previous deck
|
||||||
assert c.did == 1
|
assert c.did == 1
|
||||||
# cram the deck again
|
# cram the deck again
|
||||||
|
@ -702,12 +703,12 @@ def test_cram_rem():
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
# answering the card will put it in the learning queue
|
# answering the card will put it in the learning queue
|
||||||
assert c.type == c.queue == 1
|
assert c.type == CARD_TYPE_LRN and c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.due != oldDue
|
assert c.due != oldDue
|
||||||
# if we terminate cramming prematurely it should be set back to new
|
# if we terminate cramming prematurely it should be set back to new
|
||||||
d.sched.emptyDyn(did)
|
d.sched.emptyDyn(did)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.type == c.queue == 0
|
assert c.type == CARD_TYPE_NEW and c.queue == QUEUE_TYPE_NEW
|
||||||
assert c.due == oldDue
|
assert c.due == oldDue
|
||||||
|
|
||||||
|
|
||||||
|
@ -731,10 +732,11 @@ def test_cram_resched():
|
||||||
assert ni(c, 3) == 0
|
assert ni(c, 3) == 0
|
||||||
assert d.sched.nextIvlStr(c, 3) == "(end)"
|
assert d.sched.nextIvlStr(c, 3) == "(end)"
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.queue == c.type == 0
|
assert c.type == CARD_TYPE_NEW and c.queue == QUEUE_TYPE_NEW
|
||||||
# undue reviews should also be unaffected
|
# undue reviews should also be unaffected
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.type = c.queue = 2
|
c.queue = CARD_TYPE_REV
|
||||||
|
c.type = QUEUE_TYPE_REV
|
||||||
c.due = d.sched.today + 25
|
c.due = d.sched.today + 25
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
c.flush()
|
c.flush()
|
||||||
|
@ -911,8 +913,8 @@ def test_repCounts():
|
||||||
f["Front"] = "three"
|
f["Front"] = "three"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = d.sched.today
|
c.due = d.sched.today
|
||||||
c.flush()
|
c.flush()
|
||||||
d.reset()
|
d.reset()
|
||||||
|
@ -929,8 +931,8 @@ def test_timing():
|
||||||
f["Front"] = "num" + str(i)
|
f["Front"] = "num" + str(i)
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.flush()
|
c.flush()
|
||||||
# fail the first one
|
# fail the first one
|
||||||
|
@ -941,7 +943,7 @@ def test_timing():
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
# the next card should be another review
|
# the next card should be another review
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
# but if we wait for a second, the failed card should come back
|
# but if we wait for a second, the failed card should come back
|
||||||
orig_time = time.time
|
orig_time = time.time
|
||||||
|
|
||||||
|
@ -950,7 +952,7 @@ def test_timing():
|
||||||
|
|
||||||
time.time = adjusted_time
|
time.time = adjusted_time
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
time.time = orig_time
|
time.time = orig_time
|
||||||
|
|
||||||
|
|
||||||
|
@ -982,7 +984,7 @@ def test_deckDue():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# make it a review card
|
# make it a review card
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.flush()
|
c.flush()
|
||||||
# add one more with a new deck
|
# add one more with a new deck
|
||||||
|
@ -1100,8 +1102,8 @@ def test_forget():
|
||||||
f["Front"] = "one"
|
f["Front"] = "one"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.flush()
|
c.flush()
|
||||||
|
@ -1122,7 +1124,7 @@ def test_resched():
|
||||||
c.load()
|
c.load()
|
||||||
assert c.due == d.sched.today
|
assert c.due == d.sched.today
|
||||||
assert c.ivl == 1
|
assert c.ivl == 1
|
||||||
assert c.queue == c.type == 2
|
assert c.queue == CARD_TYPE_REV and c.type == QUEUE_TYPE_REV
|
||||||
d.sched.reschedCards([c.id], 1, 1)
|
d.sched.reschedCards([c.id], 1, 1)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.due == d.sched.today + 1
|
assert c.due == d.sched.today + 1
|
||||||
|
@ -1136,8 +1138,8 @@ def test_norelearn():
|
||||||
f["Front"] = "one"
|
f["Front"] = "one"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
c.reps = 3
|
c.reps = 3
|
||||||
|
@ -1158,8 +1160,8 @@ def test_failmult():
|
||||||
f["Back"] = "two"
|
f["Back"] = "two"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.due = d.sched.today - c.ivl
|
c.due = d.sched.today - c.ivl
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
|
|
|
@ -4,7 +4,7 @@ import copy
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.consts import STARTING_FACTOR
|
from anki.consts import *
|
||||||
from anki.utils import intTime
|
from anki.utils import intTime
|
||||||
from tests.shared import getEmptyCol as getEmptyColOrig
|
from tests.shared import getEmptyCol as getEmptyColOrig
|
||||||
|
|
||||||
|
@ -57,13 +57,13 @@ def test_new():
|
||||||
# fetch it
|
# fetch it
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
assert c
|
assert c
|
||||||
assert c.queue == 0
|
assert c.queue == QUEUE_TYPE_NEW
|
||||||
assert c.type == 0
|
assert c.type == CARD_TYPE_NEW
|
||||||
# if we answer it, it should become a learn card
|
# if we answer it, it should become a learn card
|
||||||
t = intTime()
|
t = intTime()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 1
|
assert c.type == CARD_TYPE_LRN
|
||||||
assert c.due >= t
|
assert c.due >= t
|
||||||
|
|
||||||
# disabled for now, as the learn fudging makes this randomly fail
|
# disabled for now, as the learn fudging makes this randomly fail
|
||||||
|
@ -176,11 +176,11 @@ def test_learn():
|
||||||
assert c.left % 1000 == 1
|
assert c.left % 1000 == 1
|
||||||
assert c.left // 1000 == 1
|
assert c.left // 1000 == 1
|
||||||
# the next pass should graduate the card
|
# the next pass should graduate the card
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 1
|
assert c.type == CARD_TYPE_LRN
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
assert c.type == 2
|
assert c.type == CARD_TYPE_REV
|
||||||
# should be due tomorrow, with an interval of 1
|
# should be due tomorrow, with an interval of 1
|
||||||
assert c.due == d.sched.today + 1
|
assert c.due == d.sched.today + 1
|
||||||
assert c.ivl == 1
|
assert c.ivl == 1
|
||||||
|
@ -188,8 +188,8 @@ def test_learn():
|
||||||
c.type = 0
|
c.type = 0
|
||||||
c.queue = 1
|
c.queue = 1
|
||||||
d.sched.answerCard(c, 4)
|
d.sched.answerCard(c, 4)
|
||||||
assert c.type == 2
|
assert c.type == CARD_TYPE_REV
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
assert checkRevIvl(d, c, 4)
|
assert checkRevIvl(d, c, 4)
|
||||||
# revlog should have been updated each time
|
# revlog should have been updated each time
|
||||||
assert d.db.scalar("select count() from revlog where type = 0") == 5
|
assert d.db.scalar("select count() from revlog where type = 0") == 5
|
||||||
|
@ -203,20 +203,21 @@ def test_relearn():
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.due = d.sched.today
|
c.due = d.sched.today
|
||||||
c.type = c.queue = 2
|
c.queue = CARD_TYPE_REV
|
||||||
|
c.type = QUEUE_TYPE_REV
|
||||||
c.flush()
|
c.flush()
|
||||||
|
|
||||||
# fail the card
|
# fail the card
|
||||||
d.reset()
|
d.reset()
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 3
|
assert c.type == CARD_TYPE_RELEARNING
|
||||||
assert c.ivl == 1
|
assert c.ivl == 1
|
||||||
|
|
||||||
# immediately graduate it
|
# immediately graduate it
|
||||||
d.sched.answerCard(c, 4)
|
d.sched.answerCard(c, 4)
|
||||||
assert c.queue == c.type == 2
|
assert c.queue == CARD_TYPE_REV and c.type == QUEUE_TYPE_REV
|
||||||
assert c.ivl == 2
|
assert c.ivl == 2
|
||||||
assert c.due == d.sched.today + c.ivl
|
assert c.due == d.sched.today + c.ivl
|
||||||
|
|
||||||
|
@ -229,7 +230,8 @@ def test_relearn_no_steps():
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.due = d.sched.today
|
c.due = d.sched.today
|
||||||
c.type = c.queue = 2
|
c.queue = CARD_TYPE_REV
|
||||||
|
c.type = QUEUE_TYPE_REV
|
||||||
c.flush()
|
c.flush()
|
||||||
|
|
||||||
conf = d.decks.confForDid(1)
|
conf = d.decks.confForDid(1)
|
||||||
|
@ -240,7 +242,7 @@ def test_relearn_no_steps():
|
||||||
d.reset()
|
d.reset()
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.type == c.queue == 2
|
assert c.queue == CARD_TYPE_REV and c.type == QUEUE_TYPE_REV
|
||||||
|
|
||||||
|
|
||||||
def test_learn_collapsed():
|
def test_learn_collapsed():
|
||||||
|
@ -291,7 +293,7 @@ def test_learn_day():
|
||||||
# answering it will place it in queue 3
|
# answering it will place it in queue 3
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.due == d.sched.today + 1
|
assert c.due == d.sched.today + 1
|
||||||
assert c.queue == 3
|
assert c.queue == QUEUE_TYPE_DAY_LEARN_RELEARN
|
||||||
assert not d.sched.getCard()
|
assert not d.sched.getCard()
|
||||||
# for testing, move it back a day
|
# for testing, move it back a day
|
||||||
c.due -= 1
|
c.due -= 1
|
||||||
|
@ -303,7 +305,7 @@ def test_learn_day():
|
||||||
assert ni(c, 3) == 86400 * 2
|
assert ni(c, 3) == 86400 * 2
|
||||||
# if we fail it, it should be back in the correct queue
|
# if we fail it, it should be back in the correct queue
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
d.undo()
|
d.undo()
|
||||||
d.reset()
|
d.reset()
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
|
@ -315,7 +317,7 @@ def test_learn_day():
|
||||||
# the last pass should graduate it into a review card
|
# the last pass should graduate it into a review card
|
||||||
assert ni(c, 3) == 86400
|
assert ni(c, 3) == 86400
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.queue == c.type == 2
|
assert c.queue == CARD_TYPE_REV and c.type == QUEUE_TYPE_REV
|
||||||
# if the lapse step is tomorrow, failing it should handle the counts
|
# if the lapse step is tomorrow, failing it should handle the counts
|
||||||
# correctly
|
# correctly
|
||||||
c.due = 0
|
c.due = 0
|
||||||
|
@ -325,7 +327,7 @@ def test_learn_day():
|
||||||
d.sched._cardConf(c)["lapse"]["delays"] = [1440]
|
d.sched._cardConf(c)["lapse"]["delays"] = [1440]
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.queue == 3
|
assert c.queue == QUEUE_TYPE_DAY_LEARN_RELEARN
|
||||||
assert d.sched.counts() == (0, 0, 0)
|
assert d.sched.counts() == (0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -338,8 +340,8 @@ def test_reviews():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# set the card up as a review card, due 8 days ago
|
# set the card up as a review card, due 8 days ago
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = d.sched.today - 8
|
c.due = d.sched.today - 8
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
c.reps = 3
|
c.reps = 3
|
||||||
|
@ -355,7 +357,7 @@ def test_reviews():
|
||||||
c.flush()
|
c.flush()
|
||||||
d.reset()
|
d.reset()
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
# the new interval should be (100) * 1.2 = 120
|
# the new interval should be (100) * 1.2 = 120
|
||||||
assert checkRevIvl(d, c, 120)
|
assert checkRevIvl(d, c, 120)
|
||||||
assert c.due == d.sched.today + c.ivl
|
assert c.due == d.sched.today + c.ivl
|
||||||
|
@ -398,9 +400,9 @@ def test_reviews():
|
||||||
hooks.card_did_leech.append(onLeech)
|
hooks.card_did_leech.append(onLeech)
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert hooked
|
assert hooked
|
||||||
assert c.queue == -1
|
assert c.queue == QUEUE_TYPE_SUSPENDED
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == -1
|
assert c.queue == QUEUE_TYPE_SUSPENDED
|
||||||
|
|
||||||
|
|
||||||
def test_review_limits():
|
def test_review_limits():
|
||||||
|
@ -432,7 +434,8 @@ def test_review_limits():
|
||||||
|
|
||||||
# make them reviews
|
# make them reviews
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.queue = c.type = 2
|
c.queue = CARD_TYPE_REV
|
||||||
|
c.type = QUEUE_TYPE_REV
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.flush()
|
c.flush()
|
||||||
|
|
||||||
|
@ -474,8 +477,8 @@ def test_button_spacing():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# 1 day ivl review card due now
|
# 1 day ivl review card due now
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = d.sched.today
|
c.due = d.sched.today
|
||||||
c.reps = 1
|
c.reps = 1
|
||||||
c.ivl = 1
|
c.ivl = 1
|
||||||
|
@ -503,7 +506,7 @@ def test_overdue_lapse():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# simulate a review that was lapsed and is now due for its normal review
|
# simulate a review that was lapsed and is now due for its normal review
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 1
|
c.queue = 1
|
||||||
c.due = -1
|
c.due = -1
|
||||||
c.odue = -1
|
c.odue = -1
|
||||||
|
@ -586,7 +589,7 @@ def test_nextIvl():
|
||||||
assert ni(c, 4) == 4 * 86400
|
assert ni(c, 4) == 4 * 86400
|
||||||
# lapsed cards
|
# lapsed cards
|
||||||
##################################################
|
##################################################
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
assert ni(c, 1) == 60
|
assert ni(c, 1) == 60
|
||||||
|
@ -594,7 +597,7 @@ def test_nextIvl():
|
||||||
assert ni(c, 4) == 101 * 86400
|
assert ni(c, 4) == 101 * 86400
|
||||||
# review cards
|
# review cards
|
||||||
##################################################
|
##################################################
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
# failing it should put it at 60s
|
# failing it should put it at 60s
|
||||||
|
@ -624,25 +627,25 @@ def test_bury():
|
||||||
# burying
|
# burying
|
||||||
d.sched.buryCards([c.id], manual=True) # pylint: disable=unexpected-keyword-arg
|
d.sched.buryCards([c.id], manual=True) # pylint: disable=unexpected-keyword-arg
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == -3
|
assert c.queue == QUEUE_TYPE_MANUALLY_BURIED
|
||||||
d.sched.buryCards([c2.id], manual=False) # pylint: disable=unexpected-keyword-arg
|
d.sched.buryCards([c2.id], manual=False) # pylint: disable=unexpected-keyword-arg
|
||||||
c2.load()
|
c2.load()
|
||||||
assert c2.queue == -2
|
assert c2.queue == QUEUE_TYPE_SIBLING_BURIED
|
||||||
|
|
||||||
d.reset()
|
d.reset()
|
||||||
assert not d.sched.getCard()
|
assert not d.sched.getCard()
|
||||||
|
|
||||||
d.sched.unburyCardsForDeck(type="manual") # pylint: disable=unexpected-keyword-arg
|
d.sched.unburyCardsForDeck(type="manual") # pylint: disable=unexpected-keyword-arg
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == 0
|
assert c.queue == QUEUE_TYPE_NEW
|
||||||
c2.load()
|
c2.load()
|
||||||
assert c2.queue == -2
|
assert c2.queue == QUEUE_TYPE_SIBLING_BURIED
|
||||||
|
|
||||||
d.sched.unburyCardsForDeck( # pylint: disable=unexpected-keyword-arg
|
d.sched.unburyCardsForDeck( # pylint: disable=unexpected-keyword-arg
|
||||||
type="siblings"
|
type="siblings"
|
||||||
)
|
)
|
||||||
c2.load()
|
c2.load()
|
||||||
assert c2.queue == 0
|
assert c2.queue == QUEUE_TYPE_NEW
|
||||||
|
|
||||||
d.sched.buryCards([c.id, c2.id])
|
d.sched.buryCards([c.id, c2.id])
|
||||||
d.sched.unburyCardsForDeck(type="all") # pylint: disable=unexpected-keyword-arg
|
d.sched.unburyCardsForDeck(type="all") # pylint: disable=unexpected-keyword-arg
|
||||||
|
@ -671,21 +674,21 @@ def test_suspend():
|
||||||
# should cope with rev cards being relearnt
|
# should cope with rev cards being relearnt
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.flush()
|
c.flush()
|
||||||
d.reset()
|
d.reset()
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
assert c.due >= time.time()
|
assert c.due >= time.time()
|
||||||
due = c.due
|
due = c.due
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 3
|
assert c.type == CARD_TYPE_RELEARNING
|
||||||
d.sched.suspendCards([c.id])
|
d.sched.suspendCards([c.id])
|
||||||
d.sched.unsuspendCards([c.id])
|
d.sched.unsuspendCards([c.id])
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.type == 3
|
assert c.type == CARD_TYPE_RELEARNING
|
||||||
assert c.due == due
|
assert c.due == due
|
||||||
# should cope with cards in cram decks
|
# should cope with cards in cram decks
|
||||||
c.due = 1
|
c.due = 1
|
||||||
|
@ -709,7 +712,8 @@ def test_filt_reviewing_early_normal():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.type = c.queue = 2
|
c.queue = CARD_TYPE_REV
|
||||||
|
c.type = QUEUE_TYPE_REV
|
||||||
# due in 25 days, so it's been waiting 75 days
|
# due in 25 days, so it's been waiting 75 days
|
||||||
c.due = d.sched.today + 25
|
c.due = d.sched.today + 25
|
||||||
c.mod = 1
|
c.mod = 1
|
||||||
|
@ -740,7 +744,7 @@ def test_filt_reviewing_early_normal():
|
||||||
assert c.due == d.sched.today + c.ivl
|
assert c.due == d.sched.today + c.ivl
|
||||||
assert not c.odue
|
assert not c.odue
|
||||||
# should not be in learning
|
# should not be in learning
|
||||||
assert c.queue == 2
|
assert c.queue == QUEUE_TYPE_REV
|
||||||
# should be logged as a cram rep
|
# should be logged as a cram rep
|
||||||
assert d.db.scalar("select type from revlog order by id desc limit 1") == 3
|
assert d.db.scalar("select type from revlog order by id desc limit 1") == 3
|
||||||
|
|
||||||
|
@ -771,11 +775,11 @@ def test_filt_keep_lrn_state():
|
||||||
|
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
|
|
||||||
assert c.type == c.queue == 1
|
assert c.type == CARD_TYPE_LRN and c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.left == 3003
|
assert c.left == 3003
|
||||||
|
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.type == c.queue == 1
|
assert c.type == CARD_TYPE_LRN and c.queue == QUEUE_TYPE_LRN
|
||||||
|
|
||||||
# create a dynamic deck and refresh it
|
# create a dynamic deck and refresh it
|
||||||
did = d.decks.newDyn("Cram")
|
did = d.decks.newDyn("Cram")
|
||||||
|
@ -784,7 +788,7 @@ def test_filt_keep_lrn_state():
|
||||||
|
|
||||||
# card should still be in learning state
|
# card should still be in learning state
|
||||||
c.load()
|
c.load()
|
||||||
assert c.type == c.queue == 1
|
assert c.type == CARD_TYPE_LRN and c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.left == 2002
|
assert c.left == 2002
|
||||||
|
|
||||||
# should be able to advance learning steps
|
# should be able to advance learning steps
|
||||||
|
@ -795,7 +799,7 @@ def test_filt_keep_lrn_state():
|
||||||
# emptying the deck preserves learning state
|
# emptying the deck preserves learning state
|
||||||
d.sched.emptyDyn(did)
|
d.sched.emptyDyn(did)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.type == c.queue == 1
|
assert c.type == CARD_TYPE_LRN and c.queue == QUEUE_TYPE_LRN
|
||||||
assert c.left == 1001
|
assert c.left == 1001
|
||||||
assert c.due - intTime() > 60 * 60
|
assert c.due - intTime() > 60 * 60
|
||||||
|
|
||||||
|
@ -833,9 +837,9 @@ def test_preview():
|
||||||
|
|
||||||
# passing it will remove it
|
# passing it will remove it
|
||||||
d.sched.answerCard(c2, 2)
|
d.sched.answerCard(c2, 2)
|
||||||
assert c2.queue == 0
|
assert c2.queue == QUEUE_TYPE_NEW
|
||||||
assert c2.reps == 0
|
assert c2.reps == 0
|
||||||
assert c2.type == 0
|
assert c2.type == CARD_TYPE_NEW
|
||||||
|
|
||||||
# the other card should appear again
|
# the other card should appear again
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
|
@ -844,9 +848,9 @@ def test_preview():
|
||||||
# emptying the filtered deck should restore card
|
# emptying the filtered deck should restore card
|
||||||
d.sched.emptyDyn(did)
|
d.sched.emptyDyn(did)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == 0
|
assert c.queue == QUEUE_TYPE_NEW
|
||||||
assert c.reps == 0
|
assert c.reps == 0
|
||||||
assert c.type == 0
|
assert c.type == CARD_TYPE_NEW
|
||||||
|
|
||||||
|
|
||||||
def test_ordcycle():
|
def test_ordcycle():
|
||||||
|
@ -943,8 +947,8 @@ def test_repCounts():
|
||||||
f["Front"] = "three"
|
f["Front"] = "three"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = d.sched.today
|
c.due = d.sched.today
|
||||||
c.flush()
|
c.flush()
|
||||||
d.reset()
|
d.reset()
|
||||||
|
@ -961,8 +965,8 @@ def test_timing():
|
||||||
f["Front"] = "num" + str(i)
|
f["Front"] = "num" + str(i)
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.flush()
|
c.flush()
|
||||||
# fail the first one
|
# fail the first one
|
||||||
|
@ -971,13 +975,13 @@ def test_timing():
|
||||||
d.sched.answerCard(c, 1)
|
d.sched.answerCard(c, 1)
|
||||||
# the next card should be another review
|
# the next card should be another review
|
||||||
c2 = d.sched.getCard()
|
c2 = d.sched.getCard()
|
||||||
assert c2.queue == 2
|
assert c2.queue == QUEUE_TYPE_REV
|
||||||
# if the failed card becomes due, it should show first
|
# if the failed card becomes due, it should show first
|
||||||
c.due = time.time() - 1
|
c.due = time.time() - 1
|
||||||
c.flush()
|
c.flush()
|
||||||
d.reset()
|
d.reset()
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
|
|
||||||
|
|
||||||
def test_collapse():
|
def test_collapse():
|
||||||
|
@ -1008,7 +1012,7 @@ def test_deckDue():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
# make it a review card
|
# make it a review card
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.flush()
|
c.flush()
|
||||||
# add one more with a new deck
|
# add one more with a new deck
|
||||||
|
@ -1126,8 +1130,8 @@ def test_forget():
|
||||||
f["Front"] = "one"
|
f["Front"] = "one"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.flush()
|
c.flush()
|
||||||
|
@ -1148,7 +1152,7 @@ def test_resched():
|
||||||
c.load()
|
c.load()
|
||||||
assert c.due == d.sched.today
|
assert c.due == d.sched.today
|
||||||
assert c.ivl == 1
|
assert c.ivl == 1
|
||||||
assert c.queue == c.type == 2
|
assert c.queue == QUEUE_TYPE_REV and c.type == CARD_TYPE_REV
|
||||||
d.sched.reschedCards([c.id], 1, 1)
|
d.sched.reschedCards([c.id], 1, 1)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.due == d.sched.today + 1
|
assert c.due == d.sched.today + 1
|
||||||
|
@ -1162,8 +1166,8 @@ def test_norelearn():
|
||||||
f["Front"] = "one"
|
f["Front"] = "one"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.due = 0
|
c.due = 0
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
c.reps = 3
|
c.reps = 3
|
||||||
|
@ -1184,8 +1188,8 @@ def test_failmult():
|
||||||
f["Back"] = "two"
|
f["Back"] = "two"
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.type = 2
|
c.type = CARD_TYPE_REV
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.due = d.sched.today - c.ivl
|
c.due = d.sched.today - c.ivl
|
||||||
c.factor = STARTING_FACTOR
|
c.factor = STARTING_FACTOR
|
||||||
|
@ -1217,8 +1221,8 @@ def test_moveVersions():
|
||||||
# the move to v2 should reset it to new
|
# the move to v2 should reset it to new
|
||||||
col.changeSchedulerVer(2)
|
col.changeSchedulerVer(2)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == 0
|
assert c.queue == QUEUE_TYPE_NEW
|
||||||
assert c.type == 0
|
assert c.type == CARD_TYPE_NEW
|
||||||
|
|
||||||
# fail it again, and manually bury it
|
# fail it again, and manually bury it
|
||||||
col.reset()
|
col.reset()
|
||||||
|
@ -1226,19 +1230,19 @@ def test_moveVersions():
|
||||||
col.sched.answerCard(c, 1)
|
col.sched.answerCard(c, 1)
|
||||||
col.sched.buryCards([c.id])
|
col.sched.buryCards([c.id])
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == -3
|
assert c.queue == QUEUE_TYPE_MANUALLY_BURIED
|
||||||
|
|
||||||
# revert to version 1
|
# revert to version 1
|
||||||
col.changeSchedulerVer(1)
|
col.changeSchedulerVer(1)
|
||||||
|
|
||||||
# card should have moved queues
|
# card should have moved queues
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == -2
|
assert c.queue == QUEUE_TYPE_SIBLING_BURIED
|
||||||
|
|
||||||
# and it should be new again when unburied
|
# and it should be new again when unburied
|
||||||
col.sched.unburyCards()
|
col.sched.unburyCards()
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == c.type == 0
|
assert c.type == CARD_TYPE_NEW and c.queue == QUEUE_TYPE_NEW
|
||||||
|
|
||||||
# make sure relearning cards transition correctly to v1
|
# make sure relearning cards transition correctly to v1
|
||||||
col.changeSchedulerVer(2)
|
col.changeSchedulerVer(2)
|
||||||
|
@ -1269,7 +1273,7 @@ def test_negativeDueFilter():
|
||||||
d.addNote(f)
|
d.addNote(f)
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.due = -5
|
c.due = -5
|
||||||
c.queue = 2
|
c.queue = QUEUE_TYPE_REV
|
||||||
c.ivl = 5
|
c.ivl = 5
|
||||||
c.flush()
|
c.flush()
|
||||||
|
|
||||||
|
|
|
@ -55,18 +55,18 @@ def test_review():
|
||||||
# answer
|
# answer
|
||||||
assert d.sched.counts() == (1, 0, 0)
|
assert d.sched.counts() == (1, 0, 0)
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
assert c.queue == 0
|
assert c.queue == QUEUE_TYPE_NEW
|
||||||
d.sched.answerCard(c, 3)
|
d.sched.answerCard(c, 3)
|
||||||
assert c.left == 1001
|
assert c.left == 1001
|
||||||
assert d.sched.counts() == (0, 1, 0)
|
assert d.sched.counts() == (0, 1, 0)
|
||||||
assert c.queue == 1
|
assert c.queue == QUEUE_TYPE_LRN
|
||||||
# undo
|
# undo
|
||||||
assert d.undoName()
|
assert d.undoName()
|
||||||
d.undo()
|
d.undo()
|
||||||
d.reset()
|
d.reset()
|
||||||
assert d.sched.counts() == (1, 0, 0)
|
assert d.sched.counts() == (1, 0, 0)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.queue == 0
|
assert c.queue == QUEUE_TYPE_NEW
|
||||||
assert c.left != 1001
|
assert c.left != 1001
|
||||||
assert not d.undoName()
|
assert not d.undoName()
|
||||||
# we should be able to undo multiple answers too
|
# we should be able to undo multiple answers too
|
||||||
|
|
|
@ -350,11 +350,13 @@ class DataModel(QAbstractTableModel):
|
||||||
def nextDue(self, c, index):
|
def nextDue(self, c, index):
|
||||||
if c.odid:
|
if c.odid:
|
||||||
return _("(filtered)")
|
return _("(filtered)")
|
||||||
elif c.queue == 1:
|
elif c.queue == QUEUE_TYPE_LRN:
|
||||||
date = c.due
|
date = c.due
|
||||||
elif c.queue == 0 or c.type == 0:
|
elif c.queue == QUEUE_TYPE_NEW or c.type == CARD_TYPE_NEW:
|
||||||
return str(c.due)
|
return str(c.due)
|
||||||
elif c.queue in (2, 3) or (c.type == 2 and c.queue < 0):
|
elif c.queue in (QUEUE_TYPE_REV, QUEUE_TYPE_DAY_LEARN_RELEARN) or (
|
||||||
|
c.type == CARD_TYPE_REV and c.queue < 0
|
||||||
|
):
|
||||||
date = time.time() + ((c.due - self.col.sched.today) * 86400)
|
date = time.time() + ((c.due - self.col.sched.today) * 86400)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
@ -1446,9 +1448,9 @@ border: 1px solid #000; padding: 3px; '>%s</div>"""
|
||||||
import anki.stats as st
|
import anki.stats as st
|
||||||
|
|
||||||
fmt = "<span style='color:%s'>%s</span>"
|
fmt = "<span style='color:%s'>%s</span>"
|
||||||
if type == 0:
|
if type == CARD_TYPE_NEW:
|
||||||
tstr = fmt % (st.colLearn, tstr)
|
tstr = fmt % (st.colLearn, tstr)
|
||||||
elif type == 1:
|
elif type == CARD_TYPE_LRN:
|
||||||
tstr = fmt % (st.colMature, tstr)
|
tstr = fmt % (st.colMature, tstr)
|
||||||
elif type == 2:
|
elif type == 2:
|
||||||
tstr = fmt % (st.colRelearn, tstr)
|
tstr = fmt % (st.colRelearn, tstr)
|
||||||
|
@ -1965,7 +1967,8 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||||
def _reposition(self):
|
def _reposition(self):
|
||||||
cids = self.selectedCards()
|
cids = self.selectedCards()
|
||||||
cids2 = self.col.db.list(
|
cids2 = self.col.db.list(
|
||||||
"select id from cards where type = 0 and id in " + ids2str(cids)
|
f"select id from cards where type = {CARD_TYPE_NEW} and id in "
|
||||||
|
+ ids2str(cids)
|
||||||
)
|
)
|
||||||
if not cids2:
|
if not cids2:
|
||||||
return showInfo(_("Only new cards can be repositioned."))
|
return showInfo(_("Only new cards can be repositioned."))
|
||||||
|
@ -1974,7 +1977,7 @@ update cards set usn=?, mod=?, did=? where id in """
|
||||||
frm = aqt.forms.reposition.Ui_Dialog()
|
frm = aqt.forms.reposition.Ui_Dialog()
|
||||||
frm.setupUi(d)
|
frm.setupUi(d)
|
||||||
(pmin, pmax) = self.col.db.first(
|
(pmin, pmax) = self.col.db.first(
|
||||||
"select min(due), max(due) from cards where type=0 and odid=0"
|
f"select min(due), max(due) from cards where type={CARD_TYPE_NEW} and odid=0"
|
||||||
)
|
)
|
||||||
pmin = pmin or 0
|
pmin = pmin or 0
|
||||||
pmax = pmax or 0
|
pmax = pmax or 0
|
||||||
|
|
|
@ -32,17 +32,17 @@ class CustomStudy(QDialog):
|
||||||
f.setupUi(self)
|
f.setupUi(self)
|
||||||
self.setWindowModality(Qt.WindowModal)
|
self.setWindowModality(Qt.WindowModal)
|
||||||
self.setupSignals()
|
self.setupSignals()
|
||||||
f.radio1.click()
|
f.radioNew.click()
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
def setupSignals(self):
|
def setupSignals(self):
|
||||||
f = self.form
|
f = self.form
|
||||||
f.radio1.clicked.connect(lambda: self.onRadioChange(1))
|
f.radioNew.clicked.connect(lambda: self.onRadioChange(RADIO_NEW))
|
||||||
f.radio2.clicked.connect(lambda: self.onRadioChange(2))
|
f.radioRev.clicked.connect(lambda: self.onRadioChange(RADIO_REV))
|
||||||
f.radio3.clicked.connect(lambda: self.onRadioChange(3))
|
f.radioForgot.clicked.connect(lambda: self.onRadioChange(RADIO_FORGOT))
|
||||||
f.radio4.clicked.connect(lambda: self.onRadioChange(4))
|
f.radioAhead.clicked.connect(lambda: self.onRadioChange(RADIO_AHEAD))
|
||||||
f.radio5.clicked.connect(lambda: self.onRadioChange(5))
|
f.radioPreview.clicked.connect(lambda: self.onRadioChange(RADIO_PREVIEW))
|
||||||
f.radio6.clicked.connect(lambda: self.onRadioChange(6))
|
f.radioCram.clicked.connect(lambda: self.onRadioChange(RADIO_CRAM))
|
||||||
|
|
||||||
def onRadioChange(self, idx):
|
def onRadioChange(self, idx):
|
||||||
f = self.form
|
f = self.form
|
||||||
|
|
|
@ -17,42 +17,42 @@
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QRadioButton" name="radio4">
|
<widget class="QRadioButton" name="radioAhead">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Review ahead</string>
|
<string>Review ahead</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QRadioButton" name="radio3">
|
<widget class="QRadioButton" name="radioForgot">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Review forgotten cards</string>
|
<string>Review forgotten cards</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QRadioButton" name="radio1">
|
<widget class="QRadioButton" name="radioNew">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Increase today's new card limit</string>
|
<string>Increase today's new card limit</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QRadioButton" name="radio2">
|
<widget class="QRadioButton" name="radioRev">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Increase today's review card limit</string>
|
<string>Increase today's review card limit</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="5" column="0">
|
||||||
<widget class="QRadioButton" name="radio6">
|
<widget class="QRadioButton" name="radioCram">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Study by card state or tag</string>
|
<string>Study by card state or tag</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QRadioButton" name="radio5">
|
<widget class="QRadioButton" name="radioPreview">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Preview new cards</string>
|
<string>Preview new cards</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -163,11 +163,12 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>radio1</tabstop>
|
<tabstop>radioNew</tabstop>
|
||||||
<tabstop>radio2</tabstop>
|
<tabstop>radioRev</tabstop>
|
||||||
<tabstop>radio3</tabstop>
|
<tabstop>radioForgot</tabstop>
|
||||||
<tabstop>radio4</tabstop>
|
<tabstop>radioAhead</tabstop>
|
||||||
<tabstop>radio6</tabstop>
|
<tabstop>radioPreview</tabstop>
|
||||||
|
<tabstop>radioCram</tabstop>
|
||||||
<tabstop>spin</tabstop>
|
<tabstop>spin</tabstop>
|
||||||
<tabstop>buttonBox</tabstop>
|
<tabstop>buttonBox</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
|
|
Loading…
Reference in a new issue