Exemplo n.º 1
0
    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))
Exemplo n.º 2
0
    def _update(self):
        if not self.shown:
            return
        txt = ""
        r = self.mw.reviewer
        d = self.mw.col
        cs = CardStats(d, r.card)
        cc = r.card
        if cc:
            txt += _("<h3>Current</h3>")
            txt += d.cardStats(cc)
            txt += "<p>"
            txt += self._revlogData(cc, cs)
        lc = r.lastCard()
        if lc:
            txt += _("<h3>Last</h3>")
            txt += d.cardStats(lc)
            txt += "<p>"
            txt += self._revlogData(lc, cs)
        if not txt:
            txt = _("No current card or last card.")
        style = self._style()
        self.web.setHtml("""
<html><head>
</head><style>%s</style>
<body><center>%s</center></body></html>""" % (style, txt))
Exemplo n.º 3
0
    def _cardInfoData(self):
        from anki.stats import CardStats
        cs = CardStats(self.col, self.card)
        rep = cs.report()
        rep = "<style>table * { font-size: 12px; }</style>" + rep
        m = self.card.model()
        rep = """
<div style='width: 400px; margin: 0 auto 0;
border: 1px solid #000; padding: 3px; '>%s</div>""" % rep
        return rep, cs
Exemplo n.º 4
0
    def __init__(self, parent: QWidget, mw: aqt.AnkiQt, card: Card) -> None:
        super().__init__(parent)
        disable_help_button(self)
        cs = CardStats(mw.col, card)
        info = cs.report(include_revlog=True)

        l = QVBoxLayout()
        l.setContentsMargins(0, 0, 0, 0)
        w = AnkiWebView(title="browser card info")
        l.addWidget(w)
        w.stdHtml(info + "<p>", context=self)
        bb = QDialogButtonBox(QDialogButtonBox.Close)
        l.addWidget(bb)
        qconnect(bb.rejected, self.reject)
        self.setLayout(l)
        self.setWindowModality(Qt.WindowModal)
        self.resize(500, 400)
        restoreGeom(self, "revlog")
        self.show()
Exemplo n.º 5
0
    def cardStats(self, card: Card) -> str:
        from anki.stats import CardStats

        return CardStats(self, card).report()
Exemplo n.º 6
0
    def onAdvBrowserLoad(self, advBrowser):
        """Called when the Advanced Browser add-on has finished
        loading. Create and add all custom columns owned by this
        module."""

        # Store a list of CustomColumns managed by this module. We later
        # use this to build our part of the context menu.
        self.customColumns = []

        # Convenience method to create lambdas without scope clobbering
        def getOnSort(f):
            return lambda: f

        # Dummy CardStats object so we can use the time() function without
        # creating the object every time.
        cs = CardStats(None, None)

        # -- Columns -- #

        # First review
        def cFirstOnData(c, n, t):
            first = mw.col.db.scalar(
                "select min(id) from revlog where cid = ?", c.id)
            if first:
                return time.strftime("%Y-%m-%d", time.localtime(first / 1000))

        cc = advBrowser.newCustomColumn(
            type='cfirst',
            name='First Review',
            onData=cFirstOnData,
            onSort=lambda: "(select min(id) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Last review
        def cLastOnData(c, n, t):
            last = mw.col.db.scalar("select max(id) from revlog where cid = ?",
                                    c.id)
            if last:
                return time.strftime("%Y-%m-%d", time.localtime(last / 1000))

        cc = advBrowser.newCustomColumn(
            type='clast',
            name='Last Review',
            onData=cLastOnData,
            onSort=lambda: "(select max(id) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Average time
        def cAvgtimeOnData(c, n, t):
            avgtime = mw.col.db.scalar(
                "select avg(time)/1000.0 from revlog where cid = ?", c.id)
            return self.timeFmt(avgtime)

        cc = advBrowser.newCustomColumn(
            type='cavgtime',
            name='Time (Average)',
            onData=cAvgtimeOnData,
            onSort=lambda: "(select avg(time) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Total time
        def cTottimeOnData(c, n, t):
            tottime = mw.col.db.scalar(
                "select sum(time)/1000.0 from revlog where cid = ?", c.id)
            return self.timeFmt(tottime)

        cc = advBrowser.newCustomColumn(
            type='ctottime',
            name='Time (Total)',
            onData=cTottimeOnData,
            onSort=lambda: "(select sum(time) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Fastest time
        def cFasttimeOnData(c, n, t):
            tm = mw.col.db.scalar(
                "select time/1000.0 from revlog where cid = ? "
                "order by time asc limit 1", c.id)
            return self.timeFmt(tm)

        srt = ("(select time/1000.0 from revlog where cid = c.id "
               "order by time asc limit 1)")

        cc = advBrowser.newCustomColumn(type='cfasttime',
                                        name='Fastest Review',
                                        onData=cFasttimeOnData,
                                        onSort=getOnSort(srt))
        self.customColumns.append(cc)

        # Slowest time
        def cSlowtimeOnData(c, n, t):
            tm = mw.col.db.scalar(
                "select time/1000.0 from revlog where cid = ? "
                "order by time desc limit 1", c.id)
            return self.timeFmt(tm)

        srt = ("(select time/1000.0 from revlog where cid = c.id "
               "order by time desc limit 1)")

        cc = advBrowser.newCustomColumn(type='cslowtime',
                                        name='Slowest Review',
                                        onData=cSlowtimeOnData,
                                        onSort=getOnSort(srt))
        self.customColumns.append(cc)

        # Tags
        cc = advBrowser.newCustomColumn(
            type='ntags',
            name='Tags',
            onData=lambda c, n, t: " ".join(unicode(tag) for tag in n.tags),
            # Lazy shortcut. Treat the "Tags" column as if it were a note field
            # (it is!) so we get all the benefits of our custom work on those
            # fields.
            onSort=lambda: "(select valueForField(mid, flds, 'Tags') "
            "from notes where id = c.nid)",
        )
        self.customColumns.append(cc)
        # Remove the built-in tags column.
        advBrowser.removeColumn("noteTags")

        # Overdue interval
        def cOverdueIvl(c, n, t):
            val = self.valueForOverdue(c.odid, c.queue, c.type, c.due)
            if val:
                return str(val) + " day" + ('s' if val > 1 else '')

        srt = ("(select valueForOverdue(odid, queue, type, due) "
               "from cards where id = c.id)")

        cc = advBrowser.newCustomColumn(type='coverdueivl',
                                        name="Overdue Interval",
                                        onData=cOverdueIvl,
                                        onSort=getOnSort(srt))
        self.customColumns.append(cc)

        # Previous interval
        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)

        srt = ("(select ivl from revlog where cid = c.id "
               "order by id desc limit 1 offset 1)")

        cc = advBrowser.newCustomColumn(type='cprevivl',
                                        name="Previous Interval",
                                        onData=cPrevIvl,
                                        onSort=getOnSort(srt))
        self.customColumns.append(cc)

        # Percent correct
        def cPctCorrect(c, n, t):
            if c.reps > 0:
                return "{:2.0f}%".format(100 -
                                         ((c.lapses / float(c.reps)) * 100))
            return "0%"

        cc = advBrowser.newCustomColumn(
            type='cpct',
            name='Percent Correct',
            onData=cPctCorrect,
            onSort=lambda: "cast(c.lapses as real)/c.reps")
        self.customColumns.append(cc)

        # Previous duration
        def cPrevDur(c, n, t):
            time = mw.col.db.scalar(
                "select time/1000.0 from revlog where cid = ? "
                "order by id desc limit 1", c.id)
            return self.timeFmt(time)

        srt = ("(select time/1000.0 from revlog where cid = c.id "
               "order by id desc limit 1)")

        cc = advBrowser.newCustomColumn(type='cprevdur',
                                        name="Previous Duration",
                                        onData=cPrevDur,
                                        onSort=getOnSort(srt))
        self.customColumns.append(cc)
Exemplo n.º 7
0
    def _update(self):
        if not self.dock or not self.dock.isVisible(): return
        if freezeMode and self.type>10: return

        card = mw.reviewer.card
        txt = _("No Current Card")

        if self.type<-10:
            txt = _("No Last Card")
            card = mw.reviewer.lastCard()

        cs = CollectionStats(mw.col)
        cs.wholeCollection=True if self.type<0 else False

        if self.type==0: #review count
            txt = "<center>%s</center>" % mw.reviewer._remaining() if mw.state=="review" else '? + ? + ?'
        elif abs(self.type)==1: #todayStats
            txt = "<center>%s</center>" % cs.todayStats()
        elif abs(self.type)==2: #forecast chart
            #no filtered decks
            did=mw.col.decks.selected()
            dyn=mw.col.decks.get(did)
            if dyn['dyn'] and self.type>0:
                txt="No data for filtered decks"

            elif ANKI21:
                p=mw.mediaServer.getPort()
                txt = """
<script src="http://localhost:%d/_anki/jquery.js"></script>
<script src="http://localhost:%d/_anki/plot.js"></script>
<center>%s</center>
""" % (p,p,self.dueGraph(cs))

            else:
                txt = "<script>%s\n</script><center>%s</center>" % (
                    anki.js.jquery+anki.js.plot, self.dueGraph(cs))

        elif abs(self.type)>=90:
            txt = self.customViews(card)

        elif mw.state!='review' and self.type>10:
            txt = _("No Review Card")

        elif card: #left or right col
            cs = CardStats(mw.col, card)
            if abs(self.type)==12: #card rev log
                txt = self._revlogData(card, cs)
            else: #card stats
                txt = self.deckOptionsInfo(card)
                txt += _("<h3>Card Stats:</h3>")
                txt += self.mini_card_stats(card)
                txt +=  cs.report()

                did = card.odid if card.odid else card.did
                fdid = card.did if card.odid else 0
                deckName = mw.col.decks.get(did)['name'] #in case of filtered decks
                sis=[i for i in mw.col.db.list("select id from cards where nid=?", card.nid)]
                tags=mw.col.getNote(card.nid).stringTags()

                txt += """<table width="100%%"><tr>
<td><b>Deck ID:</b></td> <td>%d</td></tr><tr>
<td><b>Fil DID:</b></td> <td>%d</td></tr><tr>
<td><b>oDeck:</b></td> <td>%s</td></tr><tr>
<td><b>SiblingCnt:</b></td> <td>%d</td></tr><tr>
<td><b>Siblings:</b></td> <td>%s</td></tr><tr>
<td><b>Tags:</b></td> <td>%s</td>
</tr></table>""" % (did, fdid, deckName, len(sis), str(sis), tags)

        style = self._style()
        self.web.setHtml("""
<!doctype html><html><head><style>%s</style></head>
<body class="night_mode">%s</body></html>""" % (style, txt))
Exemplo n.º 8
0
    def onAdvBrowserLoad(self, advBrowser):
        """Called when the Advanced Browser add-on has finished
        loading. Create and add all custom columns owned by this
        module."""

        # Store a list of CustomColumns managed by this module. We later
        # use this to build our part of the context menu.
        self.customColumns = []

        # Convenience method to create lambdas without scope clobbering
        def getOnSort(f):
            return lambda: f

        # Dummy CardStats object so we can use the time() function without
        # creating the object every time.
        cs = CardStats(None, None)

        # -- Columns -- #

        # First review
        def cFirstOnData(c, n, t):
            first = mw.col.db.scalar(
                "select min(id) from revlog where cid = ?", c.id)
            if first:
                return time.strftime("%Y-%m-%d", time.localtime(first / 1000))

        cc = advBrowser.newCustomColumn(
            type='cfirst',
            name='First Review',
            onData=cFirstOnData,
            onSort=lambda: "(select min(id) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Last review
        def cLastOnData(c, n, t):
            last = mw.col.db.scalar("select max(id) from revlog where cid = ?",
                                    c.id)
            if last:
                return time.strftime("%Y-%m-%d", time.localtime(last / 1000))

        cc = advBrowser.newCustomColumn(
            type='clast',
            name='Last Review',
            onData=cLastOnData,
            onSort=lambda: "(select max(id) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Average time
        def cAvgtimeOnData(c, n, t):
            avgtime = mw.col.db.scalar(
                "select avg(time) from revlog where cid = ?", c.id)
            if avgtime:
                return str(round(avgtime / 1000, 1)) + "s"

        cc = advBrowser.newCustomColumn(
            type='cavgtime',
            name='Time (Average)',
            onData=cAvgtimeOnData,
            onSort=lambda: "(select avg(time) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Total time
        def cTottimeOnDAta(c, n, t):
            tottime = mw.col.db.scalar(
                "select sum(time) from revlog where cid = ?", c.id)
            if tottime:
                return str(round(tottime / 1000, 1)) + "s"

        cc = advBrowser.newCustomColumn(
            type='ctottime',
            name='Time (Total)',
            onData=cTottimeOnDAta,
            onSort=lambda: "(select sum(time) from revlog where cid = c.id)")
        self.customColumns.append(cc)

        # Tags
        cc = advBrowser.newCustomColumn(
            type='ntags',
            name='Tags',
            onData=lambda c, n, t: " ".join(unicode(tag) for tag in n.tags),
            onSort=lambda: "n.tags")
        self.customColumns.append(cc)
        # Remove the built-in tags column.
        advBrowser.removeColumn("noteTags")

        # Overdue interval
        def cOverdueIvl(c, n, t):
            val = self.valueForOverdue(c.odid, c.queue, c.type, c.due)
            if val:
                return str(val) + " day" + ('s' if val > 1 else '')

        srt = ("(select valueForOverdue(odid, queue, type, due) "
               "from cards where id = c.id)")

        cc = advBrowser.newCustomColumn(type='coverdueivl',
                                        name="Overdue Interval",
                                        onData=cOverdueIvl,
                                        onSort=getOnSort(srt))
        self.customColumns.append(cc)

        # Previous interval
        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)

        srt = ("(select ivl from revlog where cid = c.id "
               "order by id desc limit 1 offset 1)")

        cc = advBrowser.newCustomColumn(type='cprevivl',
                                        name="Previous Interval",
                                        onData=cPrevIvl,
                                        onSort=getOnSort(srt))
        self.customColumns.append(cc)
Exemplo n.º 9
0
def _renderQA(self, data, qfmt=None, afmt=None, _old=None):
    """
    this function overwrites a function from collection.py
    The beginning of this function reads:
        "Returns hash of id, question, answer."
        # data is [cid, nid, mid, did, ord, tags, flds]
        # unpack fields and create dict
    """
    data = list(data)
    origFieldMap = self.models.fieldMap
    model = self.models.get(data[2])
    if data[0] is None:
        card = None
    elif data[0] == 1:
        card = None
    else:
        try:
            card = self.getCard(data[0])
        except:
            card = None

    origdata = copy.copy(data)
    data[6] += "\x1f"

    addInfo = collections.OrderedDict()

    if card is not None:
        r = mw.reviewer
        d = mw.col
        cs = CardStats(d, r.card)

        if card.odid:
            conf = d.decks.confForDid(card.odid)
        else:
            conf = d.decks.confForDid(card.did)

        (first, last, cnt, total) = self.db.first(
            "select min(id), max(id), count(), sum(time)/1000 from revlog where cid = :id",
            id=card.id)

        if cnt:
            addInfo['FirstReview'] = time.strftime(
                "%a, %d %b %Y %H:%M:%S", time.localtime(first / 1000))
            addInfo['LastReview'] = time.strftime("%a, %d %b %Y %H:%M:%S",
                                                  time.localtime(last / 1000))

            # https://docs.python.org/2/library/datetime.html  #todo
            addInfo['TimeAvg'] = timefn(total / float(cnt))
            addInfo['TimeTotal'] = timefn(total)

            cOverdueIvl = valueForOverdue(card.odid, card.queue, card.type,
                                          card.due, d)
            if cOverdueIvl:
                addInfo['overdue_fmt'] = str(cOverdueIvl) + " day" + (
                    's' if cOverdueIvl > 1 else '')
                addInfo['overdue_days'] = str(cOverdueIvl)

        model = self.models.get(data[2])
        addInfo['external_file_link'] = external_file_link(card, model)

        addInfo['Ord'] = data[4]
        addInfo['Did'] = card.did
        addInfo['Due'] = card.due
        addInfo['Id'] = card.id
        addInfo['Ivl'] = card.ivl
        addInfo['Queue'] = card.queue
        addInfo['Reviews'] = card.reps
        addInfo['Lapses'] = card.lapses
        addInfo['Type'] = card.type
        addInfo['Nid'] = card.nid
        addInfo['Mod'] = time.strftime("%Y-%m-%d", time.localtime(card.mod))
        addInfo['Usn'] = card.usn
        addInfo['Factor'] = card.factor
        addInfo['Ease'] = int(card.factor / 10)

        addInfo['Review?'] = 'Review' if card.type == 2 else ''
        addInfo['New?'] = 'New' if card.type == 0 else ''
        addInfo['Learning?'] = 'Learning' if card.type == 1 else ''
        addInfo[
            'TodayLearning?'] = 'Learning' if card.type == 1 and card.queue == 1 else ''
        addInfo[
            'DayLearning?'] = 'Learning' if card.type == 1 and card.queue == 3 else ''

        addInfo['Young'] = 'Young' if card.type == 2 and card.ivl < 21 else ''
        addInfo[
            'Mature'] = 'Mature' if card.type == 2 and card.ivl > 20 else ''

        if gc("make_deck_options_available", False):
            addInfo['Options_Group_ID'] = conf['id']
            addInfo['Options_Group_Name'] = conf['name']
            addInfo['Ignore_answer_times_longer_than'] = conf['maxTaken']
            addInfo['Show_answer_time'] = conf['timer']
            addInfo['Auto_play_audio'] = conf['autoplay']
            addInfo['When_answer_shown_replay_q'] = conf['replayq']
            addInfo['is_filtered_deck'] = conf['dyn']
            addInfo['deck_usn'] = conf['usn']
            addInfo['deck_mod_time'] = conf['mod']
            addInfo['new__steps_in_minutes'] = conf['new']['delays']
            addInfo['new__order_of_new_cards'] = conf['new']['order']
            addInfo['new__cards_per_day'] = conf['new']['perDay']
            addInfo['graduating_interval'] = conf['new']['ints'][0]
            addInfo['easy_interval'] = conf['new']['ints'][1]
            addInfo['Starting_ease'] = int(conf['new']['initialFactor'] / 10)
            addInfo['bury_related_new_cards'] = conf['new']['bury']
            addInfo['MaxiumReviewsPerDay'] = conf['rev']['perDay']
            addInfo['EasyBonus'] = int(100 * conf['rev']['ease4'])
            addInfo['IntervalModifier'] = int(100 * conf['rev']['ivlFct'])
            addInfo['MaximumInterval'] = conf['rev']['maxIvl']
            addInfo['bur_related_reviews_until_next_day'] = conf['rev']['bury']
            addInfo['lapse_learning_steps'] = conf['lapse']['delays']
            addInfo['lapse_new_ivl'] = int(100 * conf['lapse']['mult'])
            addInfo['lapse_min_ivl'] = conf['lapse']['minInt']
            addInfo['lapse_leech_threshold'] = conf['lapse']['leechFails']
            addInfo['lapse_leech_action'] = conf['lapse']['leechAction']
            addInfo['Date_Created'] = time.strftime(
                "%Y-%m-%d %H:%M:%S", time.localtime(card.nid / 1000))

        # add your additional fields here

    # for debugging quickly add all values to template
    tt = " <table>" + "\n"
    for k in addInfo.keys():
        tt += '<tr><td align="left">%s </td><td align="left">  {{info::%s}}  </td></tr> +\n' % (
            k, k)
    tt += " </table>" + "\n"
    addInfo['allfields'] = tt

    additionalFields = [""] * len(addInfo)

    for i, v in enumerate(addInfo.values()):
        additionalFields[i] = str(v)

    data[6] += "\x1f".join(
        additionalFields)  # \x1f is used as a field separator

    def tmpFieldMap(m):
        "Mapping of field name -> (ord, field)."
        d = dict((f['name'], (f['ord'], f)) for f in m['flds'])

        newFields = []
        for k in addInfo.keys():
            newFields.append('info::' + k)

        for i, f in enumerate(newFields):
            d[f] = (len(m['flds']) + i, 0)
        return d

    self.models.fieldMap = tmpFieldMap

    data = tuple(data)
    result = _old(self, data, qfmt, afmt)
    data = origdata
    self.models.fieldMap = origFieldMap
    return result
    def _update(self):
        config = mw.addonManager.getConfig(__name__)
        infobar_currentReviewCount = config[
            'Card Info sidebar_ Current Review Count']
        try:
            sidebar_PreviousCards = int(
                config['Card Info sidebar_ Number of previous cards to show'])
        except ValueError:
            sidebar_PreviousCards = 2
        if not self.shown:
            return
        txt = ""
        r = self.mw.reviewer
        d = self.mw.col
        cs = CardStats(d, r.card)
        current_card = r.card
        review_count = len(self.mw.reviewer._answeredIds)
        styles = """<style>
        .title {
          font-family: arial;
          padding-bottom: 15px;
          font-weight: bold;
        }</style>"""
        currentReviewCount = "<div class='title'>Current Card</div><div style='font-family: courier; font-size: 10px;'>Current Review Count: {}</div>".format(
            review_count)
        if current_card:
            txt += styles
            if infobar_currentReviewCount:
                txt += currentReviewCount
            else:
                txt += "<div class='title'>Current Card</div>"
            txt += d.cardStats_mod(current_card)
            txt += "<p>"
            txt += r._revlogData_mod(current_card, cs)
            card2 = r.lastCard()
            if card2 and sidebar_PreviousCards > 1:
                if sidebar_PreviousCards == 2:
                    txt += "<hr><div class='title'>Last Card</div>"
                else:
                    txt += "<hr><div class='title'>Card 2</div>"
                txt += d.cardStats_mod(card2)
                txt += "<p>"
                txt += r._revlogData_mod(card2, cs)
                if sidebar_PreviousCards < 3:
                    if infobar_currentReviewCount:
                        txt += currentReviewCount
                card3 = r.lastCard2()
                if card3 and sidebar_PreviousCards > 2:
                    txt += "<hr><div class='title''>Card 3</div>"
                    txt += d.cardStats_mod(card3)
                    txt += "<p>"
                    txt += r._revlogData_mod(card3, cs)
                    if sidebar_PreviousCards < 4:
                        if infobar_currentReviewCount:
                            txt += currentReviewCount
                    card4 = r.lastCard3()
                    if card4 and sidebar_PreviousCards > 3:
                        txt += "<hr><div class='title''>Card 4</div>"
                        txt += d.cardStats_mod(card4)
                        txt += "<p>"
                        txt += r._revlogData_mod(card4, cs)
                        if infobar_currentReviewCount:
                            txt += currentReviewCount
        if not txt:
            styles = """<style>
        .title {
          font-family: arial;
          padding-bottom: 15px;
          font-weight: bold;
        }</style>"""
            txt = styles
            card2 = r.lastCard()
            if card2 and sidebar_PreviousCards > 1:
                txt += "<div class='title'>Last Card</div>"
                txt += d.cardStats_mod(card2)
                txt += "<p>"
                txt += r._revlogData_mod(card2, cs)
                if sidebar_PreviousCards < 3:
                    if infobar_currentReviewCount:
                        txt += currentReviewCount
                card3 = r.lastCard2()
                if card3 and sidebar_PreviousCards > 2:
                    txt += "<hr><div class='title''>Card 2</div>"
                    txt += d.cardStats_mod(card3)
                    txt += "<p>"
                    txt += r._revlogData_mod(card3, cs)
                    if sidebar_PreviousCards < 4:
                        if infobar_currentReviewCount:
                            txt += currentReviewCount
                    card4 = r.lastCard3()
                    if card4 and sidebar_PreviousCards > 3:
                        txt += "<hr><div class='title''>Card 3</div>"
                        txt += d.cardStats_mod(card4)
                        txt += "<p>"
                        txt += r._revlogData_mod(card4, cs)
                        if infobar_currentReviewCount:
                            txt += currentReviewCount
        style = self._style()
        self.web.setHtml("""
<html>
    <head>
        <style>%s</style>
    </head>
        <body>
            <center>%s</center>
        </body>
</html>
""" % (style, txt))
 def cardStats_mod(self, card):
     from anki.stats import CardStats
     return CardStats(self, card).report_mod()
Exemplo n.º 12
0
 def _cardInfoData(self) -> Tuple[str, CardStats]:
     cs = CardStats(self.col, self.card)
     rep = cs.report(include_revlog=True)
     return rep, cs
Exemplo n.º 13
0
    def onAdvBrowserLoad(self, advBrowser):
        """Called when the Advanced Browser add-on has finished
        loading. Create and add all custom columns owned by this
        module."""

        # Store a list of CustomColumns managed by this module. We later
        # use this to build our part of the context menu.
        self.customColumns = []

        # Convenience method to create lambdas without scope clobbering
        def getOnSort(f): return lambda: f

        # Dummy CardStats object so we can use the time() function without
        # creating the object every time.
        cs = CardStats(None, None)

        # -- Columns -- #

        # First review
        def cFirstOnData(c, n, t):
            first = mw.col.db.scalar(
                "select min(id) from revlog where cid = ?", c.id)
            if first:
                return time.strftime("%Y-%m-%d", time.localtime(first / 1000))

        cc = advBrowser.newCustomColumn(
            type='cfirst',
            name='First Review',
            onData=cFirstOnData,
            onSort=lambda: "(select min(id) from revlog where cid = c.id)"
        )
        self.customColumns.append(cc)

        # Last review

        def cLastOnData(c, n, t):
            last = mw.col.db.scalar(
                "select max(id) from revlog where cid = ?", c.id)
            if last:
                return time.strftime("%Y-%m-%d", time.localtime(last / 1000))

        cc = advBrowser.newCustomColumn(
            type='clast',
            name='Last Review',
            onData=cLastOnData,
            onSort=lambda: "(select max(id) from revlog where cid = c.id)"
        )
        self.customColumns.append(cc)

        # Average time

        def cAvgtimeOnData(c, n, t):
            avgtime = mw.col.db.scalar(
                "select avg(time)/1000.0 from revlog where cid = ?", c.id)
            return self.timeFmt(avgtime)

        cc = advBrowser.newCustomColumn(
            type='cavgtime',
            name='Time (Average)',
            onData=cAvgtimeOnData,
            onSort=lambda: "(select avg(time) from revlog where cid = c.id)"
        )
        self.customColumns.append(cc)

        # Total time

        def cTottimeOnData(c, n, t):
            tottime = mw.col.db.scalar(
                "select sum(time)/1000.0 from revlog where cid = ?", c.id)
            return self.timeFmt(tottime)

        cc = advBrowser.newCustomColumn(
            type='ctottime',
            name='Time (Total)',
            onData=cTottimeOnData,
            onSort=lambda: "(select sum(time) from revlog where cid = c.id)"
        )
        self.customColumns.append(cc)

        # Fastest time
        def cFasttimeOnData(c, n, t):
            tm = mw.col.db.scalar(
                "select time/1000.0 from revlog where cid = ? "
                "order by time asc limit 1", c.id)
            return self.timeFmt(tm)

        srt = ("(select time/1000.0 from revlog where cid = c.id "
               "order by time asc limit 1)")

        cc = advBrowser.newCustomColumn(
            type='cfasttime',
            name='Fastest Review',
            onData=cFasttimeOnData,
            onSort=getOnSort(srt)
        )
        self.customColumns.append(cc)

        # Slowest time
        def cSlowtimeOnData(c, n, t):
            tm = mw.col.db.scalar(
                "select time/1000.0 from revlog where cid = ? "
                "order by time desc limit 1", c.id)
            return self.timeFmt(tm)

        srt = ("(select time/1000.0 from revlog where cid = c.id "
               "order by time desc limit 1)")

        cc = advBrowser.newCustomColumn(
            type='cslowtime',
            name='Slowest Review',
            onData=cSlowtimeOnData,
            onSort=getOnSort(srt)
        )
        self.customColumns.append(cc)

        # Overdue interval
        def cOverdueIvl(c, n, t):
            val = self.valueForOverdue(c.odid, c.queue, c.type, c.due)
            if val:
                return str(val) + " day" + ('s' if val > 1 else '')

        # fixme: this will need to be converted into an sql case statement
        srt = ("(select due " #valueForOverdue(odid, queue, type, due) "
               "from cards where id = c.id)")

        cc = advBrowser.newCustomColumn(
            type='coverdueivl',
            name="Overdue Interval",
            onData=cOverdueIvl,
            onSort=getOnSort(srt)
        )
        self.customColumns.append(cc)

        # Previous interval

        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)

        srt = ("(select ivl from revlog where cid = c.id "
               "order by id desc limit 1 offset 1)")

        cc = advBrowser.newCustomColumn(
            type='cprevivl',
            name="Previous Interval",
            onData=cPrevIvl,
            onSort=getOnSort(srt)
        )
        self.customColumns.append(cc)

        # Percent correct
        def cPctCorrect(c, n, t):
            if c.reps > 0:
                return "{:2.0f}%".format(
                    100 - ((c.lapses / float(c.reps)) * 100))
            return "0%"

        cc = advBrowser.newCustomColumn(
            type='cpct',
            name='Percent Correct',
            onData=cPctCorrect,
            onSort=lambda: "cast(c.lapses as real)/c.reps"
        )
        self.customColumns.append(cc)

        # Previous duration
        def cPrevDur(c, n, t):
            time = mw.col.db.scalar(
                "select time/1000.0 from revlog where cid = ? "
                "order by id desc limit 1", c.id)
            return self.timeFmt(time)

        srt = ("(select time/1000.0 from revlog where cid = c.id "
               "order by id desc limit 1)")

        cc = advBrowser.newCustomColumn(
            type='cprevdur',
            name="Previous Duration",
            onData=cPrevDur,
            onSort=getOnSort(srt)
        )
        self.customColumns.append(cc)

        # Date (and time) created
        def cDateTimeCrt(c, n, t):
            return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(c.note().id/1000))

        cc = advBrowser.newCustomColumn(
            type='cdatetimecrt',
            name='Created',
            onData=cDateTimeCrt,
            onSort=lambda: "n.id"
        )
        self.customColumns.append(cc)

        # fixme: sorting
        cc = advBrowser.newCustomColumn(
            type="cdeck",
            name="Current Deck",
            onData=lambda c, n, t: advBrowser.mw.col.decks.name(c.did),
            onSort=lambda: "c.did" # "nameForDeck(c.did)",
        )
        self.customColumns.append(cc)
Exemplo n.º 14
0
def get_all_fields(context: TemplateRenderContext) -> Dict[str, Any]:
    addInfo: Dict[str, Any] = {}
    card = context.card()

    # note: card will no longer be none, and this if statement can be removed
    if card is not None:
        r = mw.reviewer
        d = mw.col
        cs = CardStats(d, r.card)

        if card.odid:
            conf = d.decks.confForDid(card.odid)
        else:
            conf = d.decks.confForDid(card.did)

        (first, last, cnt, total) = mw.col.db.first(
            "select min(id), max(id), count(), sum(time)/1000 from revlog where cid = :id",
            id=card.id,
        )

        if cnt:
            addInfo["FirstReview"] = time.strftime(
                "%a, %d %b %Y %H:%M:%S", time.localtime(first / 1000)
            )
            addInfo["LastReview"] = time.strftime(
                "%a, %d %b %Y %H:%M:%S", time.localtime(last / 1000)
            )

            # https://docs.python.org/2/library/datetime.html  #todo
            addInfo["TimeAvg"] = timefn(total / float(cnt))
            addInfo["TimeTotal"] = timefn(total)

            cOverdueIvl = valueForOverdue(card.odid, card.queue, card.type, card.due, d)
            if cOverdueIvl:
                addInfo["overdue_fmt"] = (
                    str(cOverdueIvl) + " day" + ("s" if cOverdueIvl > 1 else "")
                )
                addInfo["overdue_days"] = str(cOverdueIvl)

        addInfo["external_file_link"] = external_file_link(card, context.note_type())

        addInfo["Ord"] = card.ord
        addInfo["Did"] = card.did
        addInfo["Due"] = card.due
        addInfo["Id"] = card.id
        addInfo["Ivl"] = card.ivl
        addInfo["Queue"] = card.queue
        addInfo["Reviews"] = card.reps
        addInfo["Lapses"] = card.lapses
        addInfo["Type"] = card.type
        addInfo["Nid"] = card.nid
        addInfo["Mod"] = time.strftime("%Y-%m-%d", time.localtime(card.mod))
        addInfo["Usn"] = card.usn
        addInfo["Factor"] = card.factor
        addInfo["Ease"] = int(card.factor / 10)

        addInfo["Review?"] = "Review" if card.type == 2 else ""
        addInfo["New?"] = "New" if card.type == 0 else ""
        addInfo["Learning?"] = "Learning" if card.type == 1 else ""
        addInfo["TodayLearning?"] = (
            "Learning" if card.type == 1 and card.queue == 1 else ""
        )
        addInfo["DayLearning?"] = (
            "Learning" if card.type == 1 and card.queue == 3 else ""
        )

        addInfo["Young"] = "Young" if card.type == 2 and card.ivl < 21 else ""
        addInfo["Mature"] = "Mature" if card.type == 2 and card.ivl > 20 else ""

        if gc("make_deck_options_available", False):
            addInfo["Options_Group_ID"] = conf["id"]
            addInfo["Options_Group_Name"] = conf["name"]
            addInfo["Ignore_answer_times_longer_than"] = conf["maxTaken"]
            addInfo["Show_answer_time"] = conf["timer"]
            addInfo["Auto_play_audio"] = conf["autoplay"]
            addInfo["When_answer_shown_replay_q"] = conf["replayq"]
            addInfo["is_filtered_deck"] = conf["dyn"]
            addInfo["deck_usn"] = conf["usn"]
            addInfo["deck_mod_time"] = conf["mod"]
            addInfo["new__steps_in_minutes"] = conf["new"]["delays"]
            addInfo["new__order_of_new_cards"] = conf["new"]["order"]
            addInfo["new__cards_per_day"] = conf["new"]["perDay"]
            addInfo["graduating_interval"] = conf["new"]["ints"][0]
            addInfo["easy_interval"] = conf["new"]["ints"][1]
            addInfo["Starting_ease"] = int(conf["new"]["initialFactor"] / 10)
            addInfo["bury_related_new_cards"] = conf["new"]["bury"]
            addInfo["MaxiumReviewsPerDay"] = conf["rev"]["perDay"]
            addInfo["EasyBonus"] = int(100 * conf["rev"]["ease4"])
            addInfo["IntervalModifier"] = int(100 * conf["rev"]["ivlFct"])
            addInfo["MaximumInterval"] = conf["rev"]["maxIvl"]
            addInfo["bur_related_reviews_until_next_day"] = conf["rev"]["bury"]
            addInfo["lapse_learning_steps"] = conf["lapse"]["delays"]
            addInfo["lapse_new_ivl"] = int(100 * conf["lapse"]["mult"])
            addInfo["lapse_min_ivl"] = conf["lapse"]["minInt"]
            addInfo["lapse_leech_threshold"] = conf["lapse"]["leechFails"]
            addInfo["lapse_leech_action"] = conf["lapse"]["leechAction"]
            addInfo["Date_Created"] = time.strftime(
                "%Y-%m-%d %H:%M:%S", time.localtime(card.nid / 1000)
            )

        # add your additional fields here

    # for debugging quickly
    tt = " <table>" + "\n"
    for k in sorted(addInfo.keys()):
        tt += '<tr><td align="left">%s </td><td align="left">  %s  </td></tr> +\n' % (
            k,
            addInfo[k],
        )
    tt += " </table>" + "\n"
    addInfo["allfields"] = tt

    return addInfo