def ivlGraph(self): (ivls, all, avg, max) = self._ivls() tot = 0 totd = [] if not ivls or not all: return "" for (grp, cnt) in ivls: tot += cnt totd.append((grp, tot / float(all) * 100)) txt = self._title(_("Intervals"), _("Delays until reviews are shown again.")) txt += self._graph(id="ivl", data=[ dict(data=ivls, color=colIvl, label=_("All Types")), dict(data=totd, color=colCum, label=_("% Total"), yaxis=2, bars={'show': False}, lines=dict(show=True), stack=False) ], conf=dict( xaxis=dict(min=-0.5, max=ivls[-1][0] + 0.5), yaxes=[dict(), dict(position="right", max=105)])) i = [] self._line(i, _("Average interval"), fmtTimeSpan(avg * 86400)) self._line(i, _("Longest interval"), fmtTimeSpan(max * 86400)) return txt + self._lineTbl(i)
def time(self, tm): str = "" if tm >= 60: str = fmtTimeSpan((tm / 60) * 60, short=True, point=-1, unit=1) if tm % 60 != 0 or not str: str += fmtTimeSpan(tm % 60, point=2 if not str else -1, short=True) return str
def ivlGraph(self): (ivls, all, avg, max) = self._ivls() tot = 0 totd = [] if not ivls or not all: return "" for (grp, cnt) in ivls: tot += cnt totd.append((grp, tot / float(all) * 100)) txt = self._title(_("Intervals"), _("Delays until reviews are shown again.")) txt += self._graph( id="ivl", data=[ dict(data=ivls, color=colIvl, label=_("All Types")), dict( data=totd, color=colCum, label=_("% Total"), yaxis=2, bars={"show": False}, lines=dict(show=True), stack=False, ), ], conf=dict(xaxis=dict(min=-0.5, max=ivls[-1][0] + 0.5), yaxes=[dict(), dict(position="right", max=105)]), ) i = [] self._line(i, _("Average interval"), fmtTimeSpan(avg * 86400)) self._line(i, _("Longest interval"), fmtTimeSpan(max * 86400)) return txt + self._lineTbl(i)
def ivlGraph(self): (ivls, all, avg, max_) = self._ivls() tot = 0 totd = [] if not ivls or not all: return "" for (grp, cnt) in ivls: tot += cnt totd.append((grp, tot/float(all)*100)) if self.type == 0: ivlmax = 31 elif self.type == 1: ivlmax = 52 else: ivlmax = max(5, ivls[-1][0] / 31) txt = self._title(_("Intervals"), _("Delays until reviews are shown again.")) txt += self._graph(id="ivl", ylabel2=_("Percentage"), data=[ dict(data=ivls, color=colIvl), dict(data=totd, color=colCum, yaxis=2, bars={'show': False}, lines=dict(show=True), stack=False) ], conf=dict( xaxis=dict(min=-0.5, max=ivlmax+0.5), yaxes=[dict(), dict(position="right", max=105)])) i = [] self._line(i, _("Average interval"), fmtTimeSpan(avg*86400)) self._line(i, _("Longest interval"), fmtTimeSpan(max_*86400)) return txt + self._lineTbl(i)
def time(self, tm): str = "" if tm >= 60: str = fmtTimeSpan((tm/60)*60, short=True, point=-1, unit=1) if tm%60 != 0 or not str: str += fmtTimeSpan(tm%60, point=2 if not str else -1, short=True) return str
def timeFmt(self, tm): # stole this from CardStats#time() str = "" if tm is None: return str if tm >= 60: str = fmtTimeSpan((tm / 60) * 60, short=True, point=-1, unit=1) if tm % 60 != 0 or not str: str += fmtTimeSpan(tm % 60, point=2 if not str else -1, short=True) return str
def nextDue(self, index): d = self.cards[index.row()][CARD_DUE] reps = self.cards[index.row()][CARD_REPS] secs = d - time.time() if secs <= 0: if not reps: return _("(new card)") else: return _("%s ago") % fmtTimeSpan(abs(secs), pad=0) else: return _("in %s") % fmtTimeSpan(secs, pad=0)
def onCellChanged(self, row, col, x, y): ci = self.form.table.currentItem() if not ci: self.form.bottomLabel.setText(_("Nothing selected.")) return r = self.items[ci] self.curRow = r self.form.bottomLabel.setText(_("""\ <b>Title</b>: %(title)s<br> <b>Tags</b>: %(tags)s<br> <b>Size</b>: %(size)0.2fKB<br> <b>Uploader</b>: %(author)s<br> <b>Downloads</b>: %(count)s<br> <b>Modified</b>: %(mod)s ago<br> <br>%(description)s""") % { 'title': r[R_TITLE], 'tags': r[R_TAGS], 'size': r[R_SIZE] / 1024.0, 'author': r[R_USERNAME], 'count': r[R_COUNT], 'mod': fmtTimeSpan(time.time() - r[R_MODIFIED]), 'description': r[R_DESCRIPTION].replace("\n", "<br>"), }) self.form.scrollAreaWidgetContents.adjustSize() self.form.scrollArea.setWidget(self.form.scrollAreaWidgetContents)
def drawFutureWarning(self): if not self.needFutureWarning(): return self.write("<span style='color: %s'>" % futureWarningColour + _("This card was due in %s.") % fmtTimeSpan( self.main.currentCard.due - time.time(), after=True) + "</span>")
def _summary(self): # summarize reps = 0 mins = 0 revC = 0 newC = 0 for d in self._decks: if d['state'] == 'ok': reps += d['reps'] mins += d['time'] revC += d['due'] newC += d['new'] line1 = ngettext( "Studied <b>%(reps)d card</b> in <b>%(time)s</b> today.", "Studied <b>%(reps)d cards</b> in <b>%(time)s</b> today.", reps) % { 'reps': reps, 'time': fmtTimeSpan(mins, point=2), } rev = ngettext("<b><font color=#0000ff>%d</font></b> review", "<b><font color=#0000ff>%d</font></b> reviews", revC) % revC new = ngettext("<b>%d</b> new card", "<b>%d</b> new cards", newC) % newC line2 = _("Due: %(rev)s, %(new)s") % {'rev': rev, 'new': new} return line1 + '<br>' + line2
def _showCardValues(self): lapses = self.card.lapses # since we just failed the card, current ivl is no use interval = fmtTimeSpan(self.card.lastIvl * 86400) ease = self.card.factor // 10 statManager = CardStats(self.mw.col, self.card) secondsSpent = self.mw.col.db.first( "select sum(time)/1000 from revlog where cid = :id", id=self.card.id)[0] totalTime = statManager.time(secondsSpent) # watch on updates: calling a private method of sched for config info leechThreshold = self.mw.col.sched._lapseConf(self.card)['leechFails'] if leechThreshold == lapses: timesLeeched = "Leech for the first time." else: beyondOne = (lapses - leechThreshold) // (leechThreshold // 2) timesLeeched = "Leeched %i times." % (beyondOne + 1) txt = ("{leechtimes}<br>" "<b>Lapses</b>: {lapses}<br>" "<b>Last interval</b>: {lastivl}<br>" "<b>Ease</b>: {ease}%<br>" "<b>Total time</b>: {ttime}") self.form.label.setText( txt.format(leechtimes=timesLeeched, lapses=lapses, lastivl=interval, ease=ease, ttime=totalTime))
def report(self): c = self.card fmt = lambda x, **kwargs: fmtTimeSpan(x, short=True, **kwargs) self.txt = "<table width=100%%>" self.addLine(_("Added"), self.date(c.crt)) first = self.deck.db.scalar( "select min(time) from revlog where cid = ?", c.id) last = self.deck.db.scalar( "select max(time) from revlog where cid = ?", c.id) if first: self.addLine(_("First Review"), self.date(first/1000)) self.addLine(_("Latest Review"), self.date(last/1000)) if c.queue in (1,2): if c.queue == 2: next = time.time()+((self.deck.sched.today - c.due)*86400) else: next = c.due next = self.date(next) self.addLine(_("Due"), next) self.addLine(_("Interval"), fmt(c.ivl * 86400)) self.addLine(_("Ease"), "%d%%" % (c.factor/10.0)) (cnt, total) = self.deck.db.first( "select count(), sum(taken)/1000 from revlog where cid = :id", id=c.id) if cnt: self.addLine(_("Average Time"), self.time(total / float(cnt))) self.addLine(_("Total Time"), self.time(total)) elif c.queue == 0: self.addLine(_("Position"), c.due) self.addLine(_("Model"), c.model().name) self.addLine(_("Template"), c.template()['name']) self.addLine(_("Current Group"), self.deck.groupName(c.gid)) self.addLine(_("Initial Group"), self.deck.groupName(c.fact().gid)) self.txt += "</table>" return self.txt
def cardGraph(self): # graph data div = self._cards() d = [] for c, (t, col) in enumerate( ((_("Mature"), colMature), (_("Young+Learn"), colYoung), (_("Unseen"), colUnseen), (_("Suspended"), colSusp))): d.append(dict(data=div[c], label=t, color=col)) # text data i = [] (c, f) = self.deck.db.first(""" select count(id), count(distinct fid) from cards where 1 """ + self._limit()) self._line(i, _("Total cards"), c) self._line(i, _("Total facts"), f) (low, avg, high) = self._factors() if low: self._line(i, _("Lowest ease factor"), "%d%%" % low) self._line(i, _("Average ease factor"), "%d%%" % avg) self._line(i, _("Highest ease factor"), "%d%%" % high) min = self.deck.db.scalar("select min(crt) from cards where 1 " + self._limit()) if min: self._line(i, _("First card created"), _("%s ago") % fmtTimeSpan(time.time() - min)) info = "<table width=100%>" + "".join(i) + "</table><p>" info += _('''\ A card's <i>ease factor</i> is the size of the next interval \ when you answer "good" on a review.''') txt = self._title(_("Cards Types"), _("The division of cards in your deck.")) txt += "<table width=%d><tr><td>%s</td><td>%s</td></table>" % ( self.width, self._graph(id="cards", data=d, type="pie"), info) return txt
def report(self): c = self.card fmt = lambda x, **kwargs: fmtTimeSpan(x, short=True, **kwargs) self.txt = "<table width=100%%>" self.addLine(_("Added"), self.date(c.crt)) first = self.deck.db.scalar( "select min(time) from revlog where cid = ?", c.id) last = self.deck.db.scalar( "select max(time) from revlog where cid = ?", c.id) if first: self.addLine(_("First Review"), self.date(first / 1000)) self.addLine(_("Latest Review"), self.date(last / 1000)) if c.queue in (1, 2): if c.queue == 2: next = time.time() + ((self.deck.sched.today - c.due) * 86400) else: next = c.due next = self.date(next) self.addLine(_("Due"), next) self.addLine(_("Interval"), fmt(c.ivl * 86400)) self.addLine(_("Ease"), "%d%%" % (c.factor / 10.0)) (cnt, total) = self.deck.db.first( "select count(), sum(taken)/1000 from revlog where cid = :id", id=c.id) if cnt: self.addLine(_("Average Time"), self.time(total / float(cnt))) self.addLine(_("Total Time"), self.time(total)) elif c.queue == 0: self.addLine(_("Position"), c.due) self.addLine(_("Model"), c.model().name) self.addLine(_("Template"), c.template()['name']) self.addLine(_("Current Group"), self.deck.groupName(c.gid)) self.addLine(_("Initial Group"), self.deck.groupName(c.fact().gid)) self.txt += "</table>" return self.txt
def _showCardValues(self): lapses = self.card.lapses # since we just failed the card, current ivl is no use interval = fmtTimeSpan(self.card.lastIvl * 86400) ease = self.card.factor // 10 statManager = CardStats(self.mw.col, self.card) secondsSpent = self.mw.col.db.first( "select sum(time)/1000 from revlog where cid = :id", id=self.card.id)[0] totalTime = statManager.time(secondsSpent) # watch on updates: calling a private method of sched for config info leechThreshold = self.mw.col.sched._lapseConf(self.card)['leechFails'] if leechThreshold == lapses: timesLeeched = "Leech for the first time." else: beyondOne = (lapses - leechThreshold) // (leechThreshold // 2) timesLeeched = "Leeched %i times." % (beyondOne + 1) txt = ("{leechtimes}<br>" "<b>Lapses</b>: {lapses}<br>" "<b>Last interval</b>: {lastivl}<br>" "<b>Ease</b>: {ease}%<br>" "<b>Total time</b>: {ttime}") self.form.label.setText(txt.format(leechtimes=timesLeeched, lapses=lapses, lastivl=interval, ease=ease, ttime=totalTime))
def onCellChanged(self, row, col, x, y): ci = self.form.table.currentItem() if not ci: self.form.bottomLabel.setText(_("Nothing selected.")) return r = self.items[ci] self.curRow = r self.form.bottomLabel.setText( _( """\ <b>Title</b>: %(title)s<br> <b>Tags</b>: %(tags)s<br> <b>Size</b>: %(size)0.2fKB<br> <b>Uploader</b>: %(author)s<br> <b>Downloads</b>: %(count)s<br> <b>Modified</b>: %(mod)s ago<br> <br>%(description)s""" ) % { "title": r[R_TITLE], "tags": r[R_TAGS], "size": r[R_SIZE] / 1024.0, "author": r[R_USERNAME], "count": r[R_COUNT], "mod": fmtTimeSpan(time.time() - r[R_MODIFIED]), "description": r[R_DESCRIPTION].replace("\n", "<br>"), } ) self.form.scrollAreaWidgetContents.adjustSize() self.form.scrollArea.setWidget(self.form.scrollAreaWidgetContents)
def formatIvlString(self, cs, ivl): if ivl == 0: return _("0d") elif ivl > 0: return fmtTimeSpan(ivl * 86400, short=True) else: return cs.time(-ivl)
def renderStats(self): if os.path.isdir("../../addons/decks_total/locale/" + anki.lang.getLang()): lang = anki.lang.getLang() else: lang = "en" t = gettext.translation('defualt', '../../addons/decks_total/locale', [lang]) translate_ = t.ugettext # Get due and new cards due = 0 new = 0 for tree in self.mw.col.sched.deckDueTree(): due += tree[2] + tree[3] new += tree[4] # Get studdied cards cards, thetime = self.mw.col.db.first( """select count(), sum(time)/1000 from revlog where id > ?""", (self.mw.col.sched.dayCutoff - 86400) * 1000) cards = cards or 0 thetime = thetime or 0 msgp1 = ngettext("%d card", "%d cards", cards) % cards # Setup data to print buf = _("Due") + ": <font color=#0a0> %(c)s </font>" % dict(c=due) \ + translate_("reviews") + ", <font color=#00a> %(d)s </font> " % dict(d=new) \ + translate_("new cards") + " <br /> " + _("Studied %(a)s in %(b)s today.") \ % dict(a=msgp1, b=fmtTimeSpan(thetime, unit=1)) return buf
def _summary(self): # summarize reps = 0 mins = 0 revC = 0 newC = 0 for d in self._decks: if d['state']=='ok': reps += d['reps'] mins += d['time'] revC += d['due'] newC += d['new'] line1 = ngettext( "Studied <b>%(reps)d card</b> in <b>%(time)s</b> today.", "Studied <b>%(reps)d cards</b> in <b>%(time)s</b> today.", reps) % { 'reps': reps, 'time': fmtTimeSpan(mins, point=2), } rev = ngettext( "<b><font color=#0000ff>%d</font></b> review", "<b><font color=#0000ff>%d</font></b> reviews", revC) % revC new = ngettext("<b>%d</b> new card", "<b>%d</b> new cards", newC) % newC line2 = _("Due: %(rev)s, %(new)s") % { 'rev': rev, 'new': new} return line1+'<br>'+line2
def formatIvlString(ivl): if ivl == 0: return "0d" elif ivl > 0: return fmtTimeSpan(ivl * 86400, short=True) else: return stattime(-ivl)
def report(self): c = self.card fmt = lambda x, **kwargs: fmtTimeSpan(x, short=True, **kwargs) self.txt = "<table width=100%>" self.addLine(_("Added"), self.date(c.id / 1000)) first = self.col.db.scalar("select min(id) from revlog where cid = ?", c.id) last = self.col.db.scalar("select max(id) from revlog where cid = ?", c.id) if first: self.addLine(_("First Review"), self.date(first / 1000)) self.addLine(_("Latest Review"), self.date(last / 1000)) if c.queue in (1, 2): if c.queue == 2: next = time.time() + ((c.due - self.col.sched.today) * 86400) else: next = c.due next = self.date(next) self.addLine(_("Due"), next) self.addLine(_("Interval"), fmt(c.ivl * 86400)) self.addLine(_("Ease"), "%d%%" % (c.factor / 10.0)) self.addLine(_("Reviews"), "%d" % c.reps) self.addLine(_("Lapses"), "%d" % c.lapses) (cnt, total) = self.col.db.first("select count(), sum(time)/1000 from revlog where cid = :id", id=c.id) if cnt: self.addLine(_("Average Time"), self.time(total / float(cnt))) self.addLine(_("Total Time"), self.time(total)) elif c.queue == 0: self.addLine(_("Position"), c.due) self.addLine(_("Card Type"), c.template()["name"]) self.addLine(_("Note Type"), c.model()["name"]) self.addLine(_("Deck"), self.col.decks.name(c.did)) self.txt += "</table>" return self.txt
def todayStats_old(self): """We need to overwrite the entire method to change the mature ivl""" b = self._title(_("Today")) # studied today lim = self._revlogLimit() if lim: lim = " and " + lim cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first( """ select count(), sum(time)/1000, 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 = 1 then 1 else 0 end), /* review */ sum(case when type = 2 then 1 else 0 end), /* relearn */ sum(case when type = 3 then 1 else 0 end) /* filter */ from revlog where id > ? """ + lim, (self.col.sched.dayCutoff - 86400) * 1000) cards = cards or 0 thetime = thetime or 0 failed = failed or 0 lrn = lrn or 0 rev = rev or 0 relrn = relrn or 0 filt = filt or 0 # studied if anki_version.startswith("2.0."): def bold(s): return "<b>" + unicode(s) + "</b>" else: def bold(s): return "<b>" + str(s) + "</b>" msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards b += _("Studied %(a)s in %(b)s today.") % dict( a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1))) # again/pass count b += "<br>" + _("Again count: %s") % bold(failed) if cards: b += " " + _("(%s correct)") % bold("%0.1f%%" % ( (1 - failed / float(cards)) * 100)) # type breakdown b += "<br>" b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt))) # mature today mcnt, msum = self.col.db.first( """ select count(), sum(case when ease = 1 then 0 else 1 end) from revlog where lastIvl >= %d and id > ?""" % MATURE_IVL + lim, (self.col.sched.dayCutoff - 86400) * 1000) b += "<br>" if mcnt: b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)" ) % dict(a=msum, b=mcnt, c=(msum / float(mcnt) * 100)) else: b += _("No mature cards were studied today.") return b
def todayStats(self): """ Copy and paste from CollectionStats.todayStats(self) Two changes made """ #DeckInformation ... changed formatting b = "" #DeckInformation ... changed to use our deck limit lim = "cid in (select id from cards where did in %s)" % self.deck_limit if lim: lim = " and " + lim cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first( """ select count(), sum(time)/1000, 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 = 1 then 1 else 0 end), /* review */ sum(case when type = 2 then 1 else 0 end), /* relearn */ sum(case when type = 3 then 1 else 0 end) /* filter */ from revlog where id > ? """ + lim, (self.col.sched.dayCutoff - 86400) * 1000) cards = cards or 0 thetime = thetime or 0 failed = failed or 0 lrn = lrn or 0 rev = rev or 0 relrn = relrn or 0 filt = filt or 0 # studied def bold(s): return "<b>" + unicode(s) + "</b>" msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards b += _("Studied %(a)s in %(b)s today.") % dict( a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1))) # again/pass count b += "<br>" + _("Again count: %s") % bold(failed) if cards: b += " " + _("(%s correct)") % bold("%0.1f%%" % ( (1 - failed / float(cards)) * 100)) # type breakdown b += "<br>" b += ( _("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt))) # mature today mcnt, msum = self.col.db.first( """ select count(), sum(case when ease = 1 then 0 else 1 end) from revlog where lastIvl >= 21 and id > ?""" + lim, (self.col.sched.dayCutoff - 86400) * 1000) b += "<br>" if mcnt: b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)" ) % dict(a=msum, b=mcnt, c=(msum / float(mcnt) * 100)) else: b += _("No mature cards were studied today.") return b
def deckOptionsInfo(self, card): if card.odid: #filtered decks txt = _("<h3>Filtered Deck Options</h3>") conf=mw.col.decks.confForDid(card.odid) filConf = mw.col.decks.confForDid(card.did) newsteps = filConf['delays'] or conf['lapse']['delays'] else: #regular decks txt = _("<h3>Deck Options</h3>") conf=mw.col.decks.confForDid(card.did) if card.type==2: #rev newsteps=conf['lapse']['delays'] else: #new newsteps=conf['new']['delays'] formatted_steps = '' for i in newsteps: formatted_steps += ' -- ' + fmtTimeSpan(i * 60, short=True) GraduatingIvl=conf['new']['ints'][0] EasyIvl=conf['new']['ints'][1] im=conf['rev']['ivlFct'] easybonus=conf['rev']['ease4'] lnivl=conf['lapse']['mult'] optiongroup=conf['name'] ogv = 0 ogr = 15 optiongroup_fmt = "" while ogv < len(optiongroup): optiongroup_fmt += optiongroup[ogv:ogv+ogr] + '\n' ogv = ogv+ogr optiongroup_fmt = optiongroup_fmt.rstrip('\n') txt += """<p><table width=100%><tr> <td align=left style='padding-right: 3px;'><b>OptGr</b></td> <td align=left style='padding-right: 3px;'><b>Step</b></td> <td align=left style='padding-right: 3px;'><b>GrIv</b></td> <td align=left style='padding-right: 3px;'><b>EaIv</b></td> <td align=left style='padding-right: 3px;'><b>EaBo</b></td> <td align=left style='padding-right: 3px;'><b>IvMo</b></td> <td align=left style='padding-right: 3px;'><b>LpIv</b></td> </tr>""" txt += "<tr>" # option group names can be very long if len(optiongroup) > 15 and MULTILINE_LONG_OPTION_GROUP_NAMES: txt += "<td align=left style='padding-right: 3px;'> %s </td>" % optiongroup_fmt else: txt += "<td align=left style='padding-right: 3px;'> %s </td>" % optiongroup txt += "<td align=left style='padding-right: 3px;'> %s </td>" % str(newsteps)[1:-1] txt += "<td align=left style='padding-right: 3px;'> %s </td>" % str(GraduatingIvl) txt += "<td align=left style='padding-right: 3px;'> %s </td>" % str(EasyIvl) txt += "<td align=left style='padding-right: 3px;'> %s </td>" % str(int(100 * easybonus)) txt += '<td align=left style="padding-right: 3px;"> <div style="color: %s;"> %s </div></td>' % ( self.critical_color(int(100 * im), IVL_MOD_COLOR_THRESHOLDS ), str(int(100 * im) )) txt += '<td align=left style="padding-right: 3px;"> <div style="color: %s;"> %s </div></td>' % ( self.critical_color(int(100 * lnivl),LAPSE_MOD_COLOR_THRESHOLDS), str(int(100 * lnivl) )) txt += "</tr>" txt += "</table></p><hr>" return txt
def _revlogData(self, card, cs): entries = self.mw.col.db.all( "select id/1000.0, ease, ivl, factor, time/1000.0, type " "from revlog where cid = ?", card.id) if not entries: return "" s = "<table width=100%%><tr><th align=left>%s</th>" % _("Date") s += ("<th align=right>%s</th>" * 6) % (_("Type"), _("Rating"), _("Interval"), "IntDate", _("Ease"), _("Time")) cnt = 0 for (date, ease, ivl, factor, taken, type) in reversed(entries): cnt += 1 s += "<tr><td>%s</td>" % time.strftime( _("<b>%Y-%m-%d</b> @ %H:%M"), time.localtime(date)) tstr = [ _("Learn"), _("Review"), _("Relearn"), _("Filtered"), _("Resched") ][type] import anki.stats as st fmt = "<span style='color:%s'>%s</span>" if type == 0: tstr = fmt % (st.colLearn, tstr) elif type == 1: tstr = fmt % (st.colMature, tstr) elif type == 2: tstr = fmt % (st.colRelearn, tstr) elif type == 3: tstr = fmt % (st.colCram, tstr) else: tstr = fmt % ("#000", tstr) if ease == 1: ease = fmt % (st.colRelearn, ease) #################### int_due = "na" if ivl > 0: int_due_date = time.localtime(date + (ivl * 24 * 60 * 60)) int_due = time.strftime(_("%Y-%m-%d"), int_due_date) #################### if ivl == 0: ivl = _("0d") elif ivl > 0: ivl = fmtTimeSpan(ivl * 86400, short=True) else: ivl = cs.time(-ivl) s += ("<td align=right>%s</td>" * 6) % ( tstr, ease, ivl, int_due, "%d%%" % (factor / 10) if factor else "", cs.time(taken)) + "</tr>" s += "</table>" if cnt < card.reps: s += _("""\ Note: Some of the history is missing. For more information, \ please see the browser documentation.""") return s
def drawFutureWarning(self): if not self.needFutureWarning(): return self.write( "<span style='color: %s'>" % futureWarningColour + _("This card was due in %s.") % fmtTimeSpan(self.main.currentCard.due - time.time(), after=True) + "</span>")
def _renderStats(self): cards, thetime = self.mw.col.db.first(""" select count(), sum(time)/1000 from revlog where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000) cards = cards or 0 thetime = thetime or 0 buf = _("Studied %(a)d cards in %(b)s today.") % dict( a=cards, b=fmtTimeSpan(thetime)) return buf
def formatComment(numberOfCards, reviewTime): from anki.lang import _, ngettext from anki.utils import fmtTimeSpan # 2 lines ripped from the anki source msgp1 = ngettext("%d card", "%d cards", numberOfCards) % numberOfCards comment = _("studied %(a)s in %(b)s") % dict( a=msgp1, b=fmtTimeSpan(reviewTime, unit=1)) return comment
def _revlogData(self, cs): entries = self.mw.col.db.all( "select id/1000.0, ease, ivl, factor, time/1000.0, type " "from revlog where cid = ?", self.card.id) if not entries: return "" s = "<table width=100%%><tr><th align=left>%s</th>" % _("Date") s += ("<th align=right>%s</th>" * 6) % ( _("Type"), _("Rating"), _("Interval"), "IntDate", _("Ease"), _("Time")) cnt = 0 for (date, ease, ivl, factor, taken, type) in reversed(entries): cnt += 1 s += "<tr><td>%s</td>" % time.strftime(_("<b>%Y-%m-%d</b> @ %H:%M"), time.localtime(date)) tstr = [_("Learn"), _("Review"), _("Relearn"), _("Filtered"), _("Resched")][type] import anki.stats as st fmt = "<span style='color:%s'>%s</span>" if type == 0: tstr = fmt % (st.colLearn, tstr) elif type == 1: tstr = fmt % (st.colMature, tstr) elif type == 2: tstr = fmt % (st.colRelearn, tstr) elif type == 3: tstr = fmt % (st.colCram, tstr) else: tstr = fmt % ("#000", tstr) if ease == 1: ease = fmt % (st.colRelearn, ease) #################### int_due = "na" if ivl > 0: int_due_date = time.localtime(date + (ivl * 24 * 60 * 60)) int_due = time.strftime(_("%Y-%m-%d"), int_due_date) #################### if ivl == 0: ivl = _("0d") elif ivl > 0: ivl = fmtTimeSpan(ivl * 86400, short=True) else: ivl = cs.time(-ivl) s += ("<td align=right>%s</td>" * 6) % ( tstr, ease, ivl, int_due , "%d%%" % (factor / 10) if factor else "", cs.time(taken)) + "</tr>" s += "</table>" if cnt < self.card.reps: s += _("""\ Note: Some of the history is missing. For more information, \ please see the browser documentation.""") return s
def nextIvlStr(self, card, ease, short=False): "Return the next interval for CARD as a string." ivl = self.nextIvl(card, ease) if not ivl: return _("(end)") s = fmtTimeSpan(ivl, short=short) if ivl < self.col.conf['collapseTime']: s = "<"+s return s
def nextIvlStr(self, card, ease, short=False): "Return the next interval for CARD as a string." ivl = self.nextIvl(card, ease) if not ivl: return _("(end)") s = fmtTimeSpan(ivl, short=short) if ivl < self.col.conf['collapseTime']: s = "<" + s return s
def _getModifierTime(self, ease): card=mw.reviewer.card modifier=int(self.btns[ease-5][1])/100.0 #zero based self.alt_sched.setModifier(modifier) if card.queue in(0,1,3): ivl=self.alt_sched.getLrnBtnIvl(card,self.count) else: ivl=self.alt_sched.getBtnIvl(card,self.count) s=fmtTimeSpan(ivl*86400,short=True) return '<span class="nobold rem_modifier rem_time%d">%s</span><br>'%(ease-MAX_DEF_BTN,s)
def _renderStats(self): cards, thetime = self.mw.col.db.first(""" select count(), sum(time)/1000 from revlog where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000) cards = cards or 0 thetime = thetime or 0 msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards buf = _("Studied %(a)s in %(b)s today.") % dict(a=msgp1, b=fmtTimeSpan(thetime, unit=1)) return buf
def cPrevIvl(c, n, t): ivl = mw.col.db.scalar("select ivl from revlog where cid = ? " "order by id desc limit 1 offset 1", c.id) if ivl is None: return elif ivl == 0: return "0 days" elif ivl > 0: return fmtTimeSpan(ivl * 86400) else: return # cs.time(-ivl)
def ivlGraph(self) -> str: (ivls, all, avg, max_), chunk = self._ivls() tot = 0 totd = [] if not ivls or not all: return "" for (grp, cnt) in ivls: tot += cnt totd.append((grp, tot / float(all) * 100)) if self.type == 0: ivlmax = 31 elif self.type == 1: ivlmax = 52 else: ivlmax = max(5, ivls[-1][0]) txt = self._title(_("Intervals"), _("Delays until reviews are shown again.")) txt += self._graph( id="ivl", ylabel2=_("Percentage"), xunit=chunk, data=[ dict(data=ivls, color=colIvl), dict( data=totd, color=colCum, yaxis=2, bars={"show": False}, lines=dict(show=True), stack=False, ), ], conf=dict( xaxis=dict(min=-0.5, max=ivlmax + 0.5), yaxes=[dict(), dict(position="right", max=105)], ), ) i: List[str] = [] self._line(i, _("Average interval"), fmtTimeSpan(avg * 86400)) self._line(i, _("Longest interval"), fmtTimeSpan(max_ * 86400)) return txt + self._lineTbl(i)
def cPrevIvl(c, n, t): ivl = mw.col.db.scalar( "select ivl from revlog where cid = ? " "order by id desc limit 1 offset 1", c.id) if ivl is None: return elif ivl == 0: return "0 days" elif ivl > 0: return fmtTimeSpan(ivl * 86400) else: return cs.time(-ivl)
def todayStats(self): """ Copy and paste from CollectionStats.todayStats(self) Two changes made """ #DeckInformation ... changed formatting b = "" #DeckInformation ... changed to use our deck limit lim = "cid in (select id from cards where did in %s)" % self.deck_limit if lim: lim = " and " + lim cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first(""" select count(), sum(time)/1000, 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 = 1 then 1 else 0 end), /* review */ sum(case when type = 2 then 1 else 0 end), /* relearn */ sum(case when type = 3 then 1 else 0 end) /* filter */ from revlog where id > ? """ + lim, (self.col.sched.dayCutoff - 86400) * 1000) cards = cards or 0 thetime = thetime or 0 failed = failed or 0 lrn = lrn or 0 rev = rev or 0 relrn = relrn or 0 filt = filt or 0 # studied def bold(s): return "<b>" + unicode(s) + "</b>" msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards b += _("Studied %(a)s in %(b)s today.") % dict( a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1))) # again/pass count b += "<br>" + _("Again count: %s") % bold(failed) if cards: b += " " + _("(%s correct)") % bold( "%0.1f%%" % ((1 - failed / float(cards)) * 100)) # type breakdown b += "<br>" b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt))) # mature today mcnt, msum = self.col.db.first(""" select count(), sum(case when ease = 1 then 0 else 1 end) from revlog where lastIvl >= 21 and id > ?""" + lim, (self.col.sched.dayCutoff - 86400) * 1000) b += "<br>" if mcnt: b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)") % dict( a=msum, b=mcnt, c=(msum / float(mcnt) * 100)) else: b += _("No mature cards were studied today.") return b
def todayStats(self): b = self._title(_("Today")) # studied today lim = self._revlogLimit() if lim: lim = " and " + lim cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first(""" select count(), sum(time)/1000, 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 = 1 then 1 else 0 end), /* review */ sum(case when type = 2 then 1 else 0 end), /* relearn */ sum(case when type = 3 then 1 else 0 end) /* filter */ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) cards = cards or 0 thetime = thetime or 0 failed = failed or 0 lrn = lrn or 0 rev = rev or 0 relrn = relrn or 0 filt = filt or 0 # studied def bold(s): return "<b>"+str(s)+"</b>" msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards if cards: b += _("Studied %(a)s %(b)s today (%(secs).1fs/card)") % dict( a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1, inTime=True)), secs=thetime/cards ) # again/pass count b += "<br>" + _("Again count: %s") % bold(failed) if cards: b += " " + _("(%s correct)") % bold( "%0.1f%%" %((1-failed/float(cards))*100)) # type breakdown b += "<br>" b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt))) # mature today mcnt, msum = self.col.db.first(""" select count(), sum(case when ease = 1 then 0 else 1 end) from revlog where lastIvl >= 21 and id > ?"""+lim, (self.col.sched.dayCutoff-86400)*1000) b += "<br>" if mcnt: b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)") % dict( a=msum, b=mcnt, c=(msum / float(mcnt) * 100)) else: b += _("No mature cards were studied today.") else: b += _("No cards have been studied today.") return b + todayStats_new(self)
def todayStats_old(self): """We need to overwrite the entire method to change the mature ivl""" b = self._title(_("Today")) # studied today lim = self._revlogLimit() if lim: lim = " and " + lim cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first(""" select count(), sum(time)/1000, 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 = 1 then 1 else 0 end), /* review */ sum(case when type = 2 then 1 else 0 end), /* relearn */ sum(case when type = 3 then 1 else 0 end) /* filter */ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) cards = cards or 0 thetime = thetime or 0 failed = failed or 0 lrn = lrn or 0 rev = rev or 0 relrn = relrn or 0 filt = filt or 0 # studied if anki_version.startswith("2.0."): def bold(s): return "<b>"+unicode(s)+"</b>" else: def bold(s): return "<b>"+str(s)+"</b>" msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards b += _("Studied %(a)s in %(b)s today.") % dict( a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1))) # again/pass count b += "<br>" + _("Again count: %s") % bold(failed) if cards: b += " " + _("(%s correct)") % bold( "%0.1f%%" %((1-failed/float(cards))*100)) # type breakdown b += "<br>" b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt))) # mature today mcnt, msum = self.col.db.first(""" select count(), sum(case when ease = 1 then 0 else 1 end) from revlog where lastIvl >= %d and id > ?""" % MATURE_IVL +lim, (self.col.sched.dayCutoff-86400)*1000) b += "<br>" if mcnt: b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)") % dict( a=msum, b=mcnt, c=(msum / float(mcnt) * 100)) else: b += _("No mature cards were studied today.") return b
def getTimeString(self, ease): assert ease > 4 if self.conf.get("show_btn_time_in_days", False): d = self._parseDays(ease) if not d: #tobe colorize red with css return '<span class="nobold rem_error">ERROR!</span><br>' s = fmtTimeSpan(d * 86400, short=True) else: s = self.btns[ease - 5][1] #zero based p = self.conf.get("button_text_prefix", "R: ") return '<span class="nobold rem_reschedule rem_time%d">%s%s</span><br>' % ( ease - 4, p, s)
def report(self) -> str: c = self.card # pylint: disable=unnecessary-lambda fmt = lambda x, **kwargs: fmtTimeSpan(x, short=True, **kwargs) self.txt = "<table width=100%>" self.addLine(_("Added"), self.date(c.id / 1000)) first = self.col.db.scalar("select min(id) from revlog where cid = ?", c.id) last = self.col.db.scalar("select max(id) from revlog where cid = ?", c.id) if first: self.addLine(_("First Review"), self.date(first / 1000)) self.addLine(_("Latest Review"), self.date(last / 1000)) if c.type in (CARD_TYPE_LRN, CARD_TYPE_REV): if c.odid or c.queue < QUEUE_TYPE_NEW: next = None else: if c.queue in (QUEUE_TYPE_REV, QUEUE_TYPE_DAY_LEARN_RELEARN): next = time.time() + ((c.due - self.col.sched.today) * 86400) else: next = c.due next = self.date(next) if next: self.addLine( self.col.backend.translate(StringsGroup.STATISTICS, "due-date"), next, ) if c.queue == QUEUE_TYPE_REV: self.addLine(_("Interval"), fmt(c.ivl * 86400)) self.addLine(_("Ease"), "%d%%" % (c.factor / 10.0)) self.addLine(_("Reviews"), "%d" % c.reps) self.addLine(_("Lapses"), "%d" % c.lapses) (cnt, total) = self.col.db.first( "select count(), sum(time)/1000 from revlog where cid = :id", id=c.id ) if cnt: self.addLine(_("Average Time"), self.time(total / float(cnt))) self.addLine(_("Total Time"), self.time(total)) elif c.queue == QUEUE_TYPE_NEW: self.addLine(_("Position"), c.due) self.addLine(_("Card Type"), c.template()["name"]) self.addLine(_("Note Type"), c.model()["name"]) self.addLine(_("Deck"), self.col.decks.name(c.did)) self.addLine(_("Note ID"), c.nid) self.addLine(_("Card ID"), c.id) self.txt += "</table>" return self.txt
def report(self): c = self.card # pylint: disable=unnecessary-lambda fmt = lambda x, **kwargs: fmtTimeSpan(x, short=True, **kwargs) self.txt = "<table width=100%>" self.addLine(_("Added"), self.date(c.id / 1000)) first = self.col.db.scalar("select min(id) from revlog where cid = ?", c.id) last = self.col.db.scalar("select max(id) from revlog where cid = ?", c.id) if first: self.addLine(_("First Review"), self.date(first / 1000)) self.addLine(_("Latest Review"), self.date(last / 1000)) if c.type in (1, 2): if c.odid or c.queue < 0: next = None else: if c.queue in (2, 3): next = time.time() + ( (c.due - self.col.sched.today) * 86400) else: next = c.due next = self.date(next) if next: self.addLine(_("Due"), next) if c.queue == 2: self.addLine(_("Interval"), fmt(c.ivl * 86400)) self.addLine(_("Ease"), "%d%%" % (c.factor / 10.0)) self.addLine(_("Reviews"), "%d" % c.reps) self.addLine(_("Lapses"), "%d" % c.lapses) (cnt, total) = self.col.db.first( "select count(), sum(time)/1000 from revlog where cid = :id", id=c.id) if cnt: self.addLine(_("Average Time"), self.time(total / float(cnt))) self.addLine(_("Total Time"), self.time(total)) elif c.queue == 0: self.addLine(_("Position"), c.due) self.addLine(_("Card Type"), c.template()['name']) self.addLine(_("Note Type"), c.model()['name']) self.addLine(_("Deck"), self.col.decks.name(c.did)) self.addLine(_("Note ID"), c.nid) self.addLine(_("Card ID"), c.id) self.txt += "</table>" return self.txt
def todayStats(self): b = self._title(_("Today")) # studied today lim = self._revlogLimit() if lim: lim = " and " + lim cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first( """ select count(), sum(time)/1000, 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 = 1 then 1 else 0 end), /* review */ sum(case when type = 2 then 1 else 0 end), /* relearn */ sum(case when type = 3 then 1 else 0 end) /* filter */ from revlog where id > ? """ + lim, (self.col.sched.dayCutoff - 86400) * 1000, ) cards = cards or 0 thetime = thetime or 0 failed = failed or 0 lrn = lrn or 0 rev = rev or 0 relrn = relrn or 0 filt = filt or 0 # studied def bold(s): return "<b>" + unicode(s) + "</b>" msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards b += _("Studied %(a)s in %(b)s today.") % dict(a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1))) # again/pass count b += "<br>" + _("Again count: %s") % bold(failed) if cards: b += " " + _("(%s correct)") % bold("%0.1f%%" % ((1 - failed / float(cards)) * 100)) # type breakdown b += "<br>" b += _("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") % dict( a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt) ) return b
def columnData(self, index): row = index.row() col = index.column() type = self.columnType(col) c = self.getCard(index) if type == "question": return self.question(c) elif type == "answer": return self.answer(c) elif type == "noteFld": f = c.note() return self.formatQA(f.fields[self.col.models.sortIdx(f.model())]) elif type == "template": return c.template()['name'] elif type == "cardDue": return self.nextDue(c, index) elif type == "noteCrt": return time.strftime("%Y-%m-%d", time.localtime(c.note().id / 1000)) elif type == "noteMod": return time.strftime("%Y-%m-%d", time.localtime(c.note().mod)) elif type == "cardMod": return time.strftime("%Y-%m-%d", time.localtime(c.mod)) elif type == "cardReps": return str(c.reps) elif type == "cardLapses": return str(c.lapses) elif type == "cardIvl": if c.type == 0: return _("(new)") return fmtTimeSpan(c.ivl * 86400) elif type == "cardEase": if c.type == 0: return _("(new)") return "%d%%" % (c.factor / 10) elif type == "deck": return self.browser.mw.col.decks.name(c.did) elif type == "ndeck": return self.browser.mw.col.decks.name(c.note().did)
def cardGraph(self): # graph data div = self._cards() d = [] for c, (t, col) in enumerate(( (_("Mature"), colMature), (_("Young+Learn"), colYoung), (_("Unseen"), colUnseen), (_("Suspended"), colSusp))): d.append(dict(data=div[c], label=t, color=col)) # text data i = [] (c, f) = self.deck.db.first(""" select count(id), count(distinct fid) from cards where 1 """ + self._limit()) self._line(i, _("Total cards"), c) self._line(i, _("Total facts"), f) (low, avg, high) = self._factors() if low: self._line(i, _("Lowest ease factor"), "%d%%" % low) self._line(i, _("Average ease factor"), "%d%%" % avg) self._line(i, _("Highest ease factor"), "%d%%" % high) min = self.deck.db.scalar( "select min(crt) from cards where 1 " + self._limit()) if min: self._line(i, _("First card created"), _("%s ago") % fmtTimeSpan( time.time() - min)) info = "<table width=100%>" + "".join(i) + "</table><p>" info += _('''\ A card's <i>ease factor</i> is the size of the next interval \ when you answer "good" on a review.''') txt = self._title(_("Cards Types"), _("The division of cards in your deck.")) txt += "<table width=%d><tr><td>%s</td><td>%s</td></table>" % ( self.width, self._graph(id="cards", data=d, type="pie"), info) return txt
def columnData(self, index): row = index.row() col = index.column() type = self.columnType(col) c = self.getCard(index) if type == "question": return self.question(c) elif type == "answer": return self.answer(c) elif type == "noteFld": f = c.note() return self.formatQA(f.fields[self.col.models.sortIdx(f.model())]) elif type == "template": return c.template()['name'] elif type == "cardDue": return self.nextDue(c, index) elif type == "noteCrt": return time.strftime("%Y-%m-%d", time.localtime(c.note().id/1000)) elif type == "noteMod": return time.strftime("%Y-%m-%d", time.localtime(c.note().mod)) elif type == "cardMod": return time.strftime("%Y-%m-%d", time.localtime(c.mod)) elif type == "cardReps": return str(c.reps) elif type == "cardLapses": return str(c.lapses) elif type == "cardIvl": if c.type == 0: return _("(new)") return fmtTimeSpan(c.ivl*86400) elif type == "cardEase": if c.type == 0: return _("(new)") return "%d%%" % (c.factor/10) elif type == "deck": return self.browser.mw.col.decks.name(c.did) elif type == "ndeck": return self.browser.mw.col.decks.name(c.note().did)
def renderStats(self): # Get data from deck tree due = new = 0 for tree in self.mw.col.sched.deckDueTree(): due += tree[2] + tree[3] new += tree[4] # Get studdied cards cards, thetime = self.mw.col.db.first( """select count(), sum(time)/1000 from revlog where id > ?""", (self.mw.col.sched.dayCutoff - 86400) * 1000) cards = cards or 0 thetime = thetime or 0 # Setup data to print msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards buf = _("Due") + ": <font color=#0a0> %(c)s </font>" % dict(c=due) \ + _("New") + ": <font color=#00a> %(d)s </font> " % dict(d=new) \ + "<br /> " \ + _("Studied %(a)s in %(b)s today.") \ % dict(a=msgp1, b=fmtTimeSpan(thetime, unit=1)) return buf
def todayStats(self): b = self._title(_("Today")) # studied today lim = self._revlogLimit() if lim: lim = " and " + lim cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first(""" select count(), sum(time)/1000, 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 = 1 then 1 else 0 end), /* review */ sum(case when type = 2 then 1 else 0 end), /* relearn */ sum(case when type = 3 then 1 else 0 end) /* filter */ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) cards = cards or 0 thetime = thetime or 0 failed = failed or 0 lrn = lrn or 0 rev = rev or 0 relrn = relrn or 0 filt = filt or 0 # studied def bold(s): return "<b>"+unicode(s)+"</b>" msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards b += _("Studied %(a)s in %(b)s today.") % dict( a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1))) # again/pass count b += "<br>" + _("Again count: %s") % bold(failed) if cards: b += " " + _("(%s correct)") % bold( "%0.1f%%" %((1-failed/float(cards))*100)) # type breakdown b += "<br>" b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt))) return b
def text_for_scheduler_comparison(card, p): txt = "" try: orig_hard_days = mw.col.sched.original_nextRevIvl(card, 2) except: return txt else: if orig_hard_days: orig_good_days = mw.col.sched.original_nextRevIvl(card, 3) orig_easy_days = mw.col.sched.original_nextRevIvl(card, 4) hard_days = mw.col.sched._nextRevIvl(card, 2) good_days = mw.col.sched._nextRevIvl(card, 3) easy_days = mw.col.sched._nextRevIvl(card, 4) row1 = [ ["", "left"], ["days(h-g-e)", "left"], ["hard(fmt)", "center"], ["good(fmt)", "center"], ["easy(fmt)", "center"], ] row2 = [ ["<b>orig:</b>", "left"], [ "{} {} {}".format(orig_hard_days, orig_good_days, orig_easy_days), "left" ], [fmtTimeSpan(orig_hard_days * 86400, short=True), "center"], [fmtTimeSpan(orig_good_days * 86400, short=True), "center"], [fmtTimeSpan(orig_easy_days * 86400, short=True), "center"], ] row3 = [ ["<b>mod:</b>", "left"], ["{} {} {}".format(hard_days, good_days, easy_days), "left"], [fmtTimeSpan(hard_days * 86400, short=True), "center"], [fmtTimeSpan(good_days * 86400, short=True), "center"], [fmtTimeSpan(easy_days * 86400, short=True), "center"], ] #show_info_length_of_sublists([row1,row2,row3]) return make_multi_column_table_first_row_bold([row1, row2, row3])
def test_fmtTimeSpan(): assert fmtTimeSpan(5) == "5 seconds" assert fmtTimeSpan(5, inTime=True) == "in 5 seconds"
def nextIvlStr(self, card, ease, short=False): "Return the next interval for CARD as a string." ivl = self.nextIvl(card, ease) if not ivl: return "" return fmtTimeSpan(ivl, short=short)
def nextIvlStr(self, card, ease, short=False): "Return the next interval for CARD as a string." return fmtTimeSpan( self.nextIvl(card, ease), short=short)
def intervalColumn(self, index): return fmtTimeSpan( self.cards[index.row()][CARD_INTERVAL]*86400)
def etaStr(self): eta = self.eta() if not eta: return "" return fmtTimeSpan(eta)