Exemplo n.º 1
0
 def drawQuestionAndAnswer(self):
     self.deck.flushMod()
     f = self.deck.newFact()
     f.tags = u""
     for field in f.fields:
         f[field.name] = field.name
     f.model = self.model
     c = Card(f, self.card)
     t = "<body><br><center>" + c.htmlQuestion() + "</center></body>"
     bg = "body { background-color: %s; }\n" % self.card.lastFontColour
     self.dialog.question.setText(
         "<style>\n" + bg + self.deck.rebuildCSS() + "</style>\n" + t)
     t = "<body><br><center>" + c.htmlAnswer() + "</center></body>"
     self.dialog.answer.setText(
         "<style>\n" + bg + self.deck.rebuildCSS() + "</style>\n" + t)
     self.main.updateViews(self.main.state)
Exemplo n.º 2
0
Arquivo: v1.py Projeto: njhsi/anki
 def _updateRevIvl(self, card: Card, ease: int) -> None:
     idealIvl = self._nextRevIvl(card, ease)
     card.ivl = min(
         max(self._adjRevIvl(card, idealIvl), card.ivl + 1),
         self._revConf(card)["maxIvl"],
     )
Exemplo n.º 3
0
Arquivo: v1.py Projeto: njhsi/anki
    def answerCard(self, card: Card, ease: int) -> None:
        self.col.log()
        assert 1 <= ease <= 4
        self.col.save_card_review_undo_info(card)
        if self._burySiblingsOnAnswer:
            self._burySiblings(card)
        card.reps += 1
        self.reps += 1
        # former is for logging new cards, latter also covers filt. decks
        card.wasNew = card.type == CARD_TYPE_NEW  # type: ignore
        wasNewQ = card.queue == QUEUE_TYPE_NEW

        new_delta = 0
        review_delta = 0

        if wasNewQ:
            # came from the new queue, move to learning
            card.queue = QUEUE_TYPE_LRN
            # if it was a new card, it's now a learning card
            if card.type == CARD_TYPE_NEW:
                card.type = CARD_TYPE_LRN
            # init reps to graduation
            card.left = self._startingLeft(card)
            # dynamic?
            if card.odid and card.type == CARD_TYPE_REV:
                if self._resched(card):
                    # reviews get their ivl boosted on first sight
                    card.ivl = self._dynIvlBoost(card)
                    card.odue = self.today + card.ivl
            new_delta = +1
        if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
            self._answerLrnCard(card, ease)
        elif card.queue == QUEUE_TYPE_REV:
            self._answerRevCard(card, ease)
            review_delta = +1
        else:
            raise Exception(f"Invalid queue '{card}'")

        self.update_stats(
            card.did,
            new_delta=new_delta,
            review_delta=review_delta,
            milliseconds_delta=+card.timeTaken(),
        )

        card.mod = intTime()
        card.usn = self.col.usn()
        card.flush()
Exemplo n.º 4
0
Arquivo: v1.py Projeto: njhsi/anki
 def _rescheduleAsRev(self, card: Card, conf: QueueConfig, early: bool) -> None:
     lapse = card.type == CARD_TYPE_REV
     if lapse:
         if self._resched(card):
             card.due = max(self.today + 1, card.odue)
         else:
             card.due = card.odue
         card.odue = 0
     else:
         self._rescheduleNew(card, conf, early)
     card.queue = QUEUE_TYPE_REV
     card.type = CARD_TYPE_REV
     # if we were dynamic, graduating means moving back to the old deck
     resched = self._resched(card)
     if card.odid:
         card.did = card.odid
         card.odue = 0
         card.odid = DeckID(0)
         # if rescheduling is off, it needs to be set back to a new card
         if not resched and not lapse:
             card.queue = QUEUE_TYPE_NEW
             card.type = CARD_TYPE_NEW
             card.due = self.col.nextID("pos")
Exemplo n.º 5
0
 def autoplay(self, card: Card) -> bool:
     print("use card.autoplay() instead of reviewer.autoplay(card)")
     return card.autoplay()
Exemplo n.º 6
0
 def setData(c: Card, value: str):
     n = c.note()
     n.setTagsFromStr(value)
     n.flush()
     advBrowser.editor.loadNote()
     return True
Exemplo n.º 7
0
def is_cloze(card: Card):
    return card.model()['type'] == MODEL_CLOZE
Exemplo n.º 8
0
 def _updateRevIvl(self, card: Card, ease: int) -> None:
     card.ivl = self._nextRevIvl(card, ease, fuzz=True)
Exemplo n.º 9
0
def templates_for_card(card: Card, browser: bool) -> Tuple[str, str]:
    template = card.template()
    q, a = browser and ("bqfmt", "bafmt") or ("qfmt", "afmt")
    return template.get(q), template.get(a)  # type: ignore
Exemplo n.º 10
0
 def _newCard(
     self,
     note: Note,
     template: Template,
     due: int,
     flush: bool = True,
     did: Optional[int] = None,
 ) -> Card:
     "Create a new card."
     card = Card(self)
     card.nid = note.id
     card.ord = template["ord"]  # type: ignore
     card.did = self.db.scalar(
         "select did from cards where nid = ? and ord = ?", card.nid,
         card.ord)
     # Use template did (deck override) if valid, otherwise did in argument, otherwise model did
     if not card.did:
         if template["did"] and str(template["did"]) in self.decks.decks:
             card.did = int(template["did"])
         elif did:
             card.did = did
         else:
             card.did = note.model()["did"]
     # if invalid did, use default instead
     deck = self.decks.get(card.did)
     assert deck
     if deck["dyn"]:
         # must not be a filtered deck
         card.did = 1
     else:
         card.did = deck["id"]
     card.due = self._dueForDid(card.did, due)
     if flush:
         card.flush()
     return card
Exemplo n.º 11
0
def run(browser):
    cards = [Card(browser.col, cid) for cid in browser.selectedCards()]
    for card in cards:
        prepare(card, browser)
    for card in cards:
        cleanCard(card, browser)
Exemplo n.º 12
0
 def answerCard(self, card: Card, ease: int) -> None:
     self.col.log()
     assert 1 <= ease <= 4
     self.col.markReview(card)
     if self._burySiblingsOnAnswer:
         self._burySiblings(card)
     card.reps += 1
     # former is for logging new cards, latter also covers filt. decks
     card.wasNew = card.type == CARD_TYPE_NEW  # type: ignore
     wasNewQ = card.queue == QUEUE_TYPE_NEW
     if wasNewQ:
         # came from the new queue, move to learning
         card.queue = QUEUE_TYPE_LRN
         # if it was a new card, it's now a learning card
         if card.type == CARD_TYPE_NEW:
             card.type = CARD_TYPE_LRN
         # init reps to graduation
         card.left = self._startingLeft(card)
         # dynamic?
         if card.odid and card.type == CARD_TYPE_REV:
             if self._resched(card):
                 # reviews get their ivl boosted on first sight
                 card.ivl = self._dynIvlBoost(card)
                 card.odue = self.today + card.ivl
         self._updateStats(card, "new")
     if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
         self._answerLrnCard(card, ease)
         if not wasNewQ:
             self._updateStats(card, "lrn")
     elif card.queue == QUEUE_TYPE_REV:
         self._answerRevCard(card, ease)
         self._updateStats(card, "rev")
     else:
         raise Exception("Invalid queue")
     self._updateStats(card, "time", card.timeTaken())
     card.mod = intTime()
     card.usn = self.col.usn()
     card.flush()
Exemplo n.º 13
0
 def __init__(self, origin: str, card: Card):
     super().__init__(origin)
     self.card_id = card.id
     self.question = card.question()
     self.answer = card.answer()
Exemplo n.º 14
0
def maobi_hook(html: str, card: Card, context: str) -> str:
    # Only show the quiz on the front side, else it can lead to rendering issues
    if context not in {"reviewQuestion", "clayoutQuestion", "previewQuestion"}:
        return html

    # This reads from the config.json in the addon folder
    maobi_config = MaobiConfig.load()

    # Search the active deck configuration
    deck_name = mw.col.decks.current()["name"]
    template_name = card.template()["name"]
    config = maobi_config.search_active_deck_config(deck_name, template_name)

    # Return if we did not find it
    if not config:
        debug(maobi_config, f"Config not found")
        return html

    if not config.enabled:
        debug(maobi_config, f"Config disabled")
        return html

    # Get the character to write and the corresponding character data
    try:
        characters, tones = _get_characters(card, config)
        characters_data = [_load_character_data(c) for c in characters]
    except MaobiException as e:
        debug(maobi_config, str(e))
        return _build_error_message(html, str(e))

    # Style the character div depending on the configuration
    styles = []

    # Add the background grid
    hanzi_grid = _build_hanzi_grid_style(config.grid)
    styles.append(hanzi_grid)

    # Load the hanzi writer JavaScript
    with open(PATH_HANZI_WRITER, "r") as f:
        hanzi_writer_script = f.read()

    # Load the maobi quiz JavaScript
    with open(PATH_QUIZ_JS, "r") as f:
        maobi_quiz_script = f.read()

    # Render the template
    data = {
        "html": html,
        "hanzi_writer_script": hanzi_writer_script,
        "maobi_quiz_script": maobi_quiz_script,
        "target_div": TARGET_DIV,
        "reveal_button": REVEAL_BUTTON,
        "restart_button": RESTART_BUTTON,
        "characters": characters,
        "tones": tones,
        "characters_data": characters_data,
        "size": config.size,
        "leniency": config.leniency / 100.0,
        "show_hint_after_misses": config.show_hint_after_misses,
        "styles": "\n".join(styles),
    }

    result = TEMPLATE.substitute(data)

    return result
Exemplo n.º 15
0
def mergeNotes(note1, note2):
    """Merge note1 and note2 following the configuration rules. If they have distinct note type, fails."""
    mw.checkpoint("Merge Notes")

    model1 = note1.model()
    model2 = note2.model()
    if model1 != model2:
        showWarning(_("Please select notes of the same type to merge them"))
        return
    merged_note = Note(mw.col, note1.model())
    new_nid = merge_id(note1, note2)

    weak = maybeGetWeakNote(note1, note2)

    overwrite_patterns = [
        re.compile(p) for p in (getUserOption("Overwrite patterns", []) or [])
    ]
    for i in range(len(merged_note.fields)):
        if maybeOverwriteField(overwrite_patterns, i, note1, note2):
            continue
        elif note1 == weak:
            merged_note.fields[i] = note2.fields[
                i] if note2.fields[i] != "" else note1.fields[i]
        elif note2 == weak:
            merged_note.fields[i] = note1.fields[
                i] if note1.fields[i] != "" else note2.fields[i]
        elif note1.fields[i] != note2.fields[i] or not getUserOption(
                "When identical keep a single field", True):
            merged_note.fields[i] = note1.fields[i] + note2.fields[i]
        else:  # identical
            merged_note.fields[i] = note1.fields[i]
    cards = dict()

    # tags
    merged_note.addTag(note1.stringTags())
    merged_note.addTag(note2.stringTags())
    merged_note.addTag(f"merged merged_{note1.id} merged_{note2.id}")

    # Choosing which card to keep
    cards_to_delete = []
    for card1 in note1.cards():
        cards[card1.ord] = card1
    for card2 in note2.cards():
        ord = card2.ord
        card1 = cards.get(ord)
        if card1 is None or card1.type == CARD_NEW or card1.ivl < card2.ivl or (
                card1.ivl == card2.ivl and card1.factor < card2.factor):
            cards[ord] = card2
            cards_to_delete.append(card1)
        else:
            cards_to_delete.append(card2)

    if getUserOption("Delete original cards", False):
        mw.col._remNotes([note1.id])
        mw.col._remNotes([note2.id])
        mw.col.remCards(
            [card.id for card in cards_to_delete if card is not None],
            notes=False)

    for card in cards.values():
        if card is None:
            continue
        if not getUserOption("Delete original cards", False):
            tmp_card = Card(mw.col)
            card.id = tmp_card.id
        card.nid = new_nid
        card.flush()
    mw.col.add_note(merged_note, 1)
    tmp_nid = merged_note.id

    mw.col.db.execute("""
    update notes
    set id=?
    where id=?
    """, new_nid, merged_note.id)

    mw.col.db.execute("""
    delete from cards
    where nid=?
    """, tmp_nid)
    merged_note.id = new_nid

    tooltip(_("Notes merged"))
    return merged_note
Exemplo n.º 16
0
 def _removeFromFiltered(self, card: Card) -> None:
     if card.odid:
         card.did = card.odid
         card.odue = 0
         card.odid = DeckId(0)
Exemplo n.º 17
0
    def fromLocalID(cls, localDeckID):
        col = mw.col
        """We create an ankiDeckManager because thats where\
             all the decks are stored"""
        ankiDeckManager = col.decks

        # After that we get the Deck we are intrested in
        ankiDeck = ankiDeckManager.get(localDeckID)

        # With this call we retrive all Card IDs
        ankiCardIDs = ankiDeckManager.cids(localDeckID)
        """with each id we create a anki Note object and\
             add it to a list for futher processing"""

        ankiNotes = []
        ankiNoteIds = []
        for cardID in ankiCardIDs:
            nid = Card(col, cardID).nid
            if nid not in ankiNoteIds:
                ankiNoteIds.append(nid)
                ankiNotes.append(Note(col, None, nid))
        modelsDic = {}
        notes = []
        """for every note object we have we retrieve the model and create\
            a AnkiPubSubNote object we add the models to a dic so that we only\
            create models once and not for every note an extra model
            Model() 1 --> * Note()"""
        for note in ankiNotes:
            modelsDic.update({note.mid: note._model})
            notes.append(AnkipubSubNote(note, col))

        # For every Model in the dic we create a AnkipubSubModel
        models = []
        for modelID, model in modelsDic.items():
            """We deepcopy the model because otherwise with the next\
                commit we would change something in the users anki database"""
            model = deepcopy(model)
            """we move the anki assign id to localID because id is used\
                 by our server as a reference"""
            model.update({'localID': modelID})
            aModel = AnkipubSubModel(model)
            models.append(aModel)
        # Create a new Deck Object which we can push later to the server
        """
            we sort all the notes belonging to our deck after the mod value,
            the one with the biggest mod value is the one note last changed
            that change also represents the last change on our deck localy so
            we use this to generate a datetime stamp to compare to the last
            change on the server
            """
        ankiNotesByDate = sorted(ankiNotes, key=lambda note: note.mod)
        if not len(ankiNotesByDate) == 0:
            lastChange = datetime.fromtimestamp(ankiNotesByDate.pop().mod)
        else:
            lastChange = datetime.today()
        creationDate = None
        remoteID = getRemoteDeckID(localDeckID)

        return cls(notes, models, ankiDeck.get('name'), ankiDeck.get('desc'),
                   lastChange, creationDate, remoteID, localDeckID)
        """# print(deck,localDeckID,notes,models,col)
Exemplo n.º 18
0
 def _updateEarlyRevIvl(self, card: Card, ease: int) -> None:
     card.ivl = self._earlyReviewIvl(card, ease)
Exemplo n.º 19
0
def set_card_absolute_due(card: Card, absolute_due: int):
    if is_card_in_a_filtered_deck(card):
        card.odue = absolute_due
    else:
        card.due = absolute_due
    card.flush()
Exemplo n.º 20
0
 def from_existing_card(card: Card, browser: bool) -> TemplateRenderContext:
     return TemplateRenderContext(card.col, card, card.note(), browser)
Exemplo n.º 21
0
from anki.cards import Card

nid = 0

for name in mw.addonManager.allAddons():
    if mw.addonManager.addonName(name) == "Straight Reward":
        am = name

cl = __import__(am).src.lib.review_hook.review_hook_closure()
cl[0]((True, 3), False, Card(mw.col, nid))
Exemplo n.º 22
0
class Reviewer:
    def __init__(self, mw: AnkiQt) -> None:
        self.mw = mw
        self.web = mw.web
        self.card: Card | None = None
        self.cardQueue: list[Card] = []
        self.previous_card: Card | None = None
        self.hadCardQueue = False
        self._answeredIds: list[CardId] = []
        self._recordedAudio: str | None = None
        self.typeCorrect: str = None  # web init happens before this is set
        self.state: str | None = None
        self._refresh_needed: RefreshNeeded | None = None
        self._v3: V3CardInfo | None = None
        self._state_mutation_key = str(random.randint(0, 2 ** 64 - 1))
        self.bottom = BottomBar(mw, mw.bottomWeb)
        self._card_info = ReviewerCardInfo(self.mw)
        self._previous_card_info = PreviousReviewerCardInfo(self.mw)
        hooks.card_did_leech.append(self.onLeech)

    def show(self) -> None:
        self.mw.setStateShortcuts(self._shortcutKeys())  # type: ignore
        self.web.set_bridge_command(self._linkHandler, self)
        self.bottom.web.set_bridge_command(self._linkHandler, ReviewerBottomBar(self))
        self._state_mutation_js = self.mw.col.get_config("cardStateCustomizer")
        self._reps: int = None
        self._refresh_needed = RefreshNeeded.QUEUES
        self.refresh_if_needed()

    # this is only used by add-ons
    def lastCard(self) -> Card | None:
        if self._answeredIds:
            if not self.card or self._answeredIds[-1] != self.card.id:
                try:
                    return self.mw.col.getCard(self._answeredIds[-1])
                except TypeError:
                    # id was deleted
                    return None
        return None

    def cleanup(self) -> None:
        gui_hooks.reviewer_will_end()
        self.card = None

    def refresh_if_needed(self) -> None:
        if self._refresh_needed is RefreshNeeded.QUEUES:
            self.mw.col.reset()
            self.nextCard()
            self.mw.fade_in_webview()
            self._refresh_needed = None
        elif self._refresh_needed is RefreshNeeded.NOTE_TEXT:
            self._redraw_current_card()
            self.mw.fade_in_webview()
            self._refresh_needed = None

    def op_executed(
        self, changes: OpChanges, handler: object | None, focused: bool
    ) -> bool:
        if handler is not self:
            if changes.study_queues:
                self._refresh_needed = RefreshNeeded.QUEUES
            elif changes.note_text:
                self._refresh_needed = RefreshNeeded.NOTE_TEXT

        if focused and self._refresh_needed:
            self.refresh_if_needed()

        return bool(self._refresh_needed)

    def _redraw_current_card(self) -> None:
        self.card.load()
        if self.state == "answer":
            self._showAnswer()
        else:
            self._showQuestion()

    # Fetching a card
    ##########################################################################

    def nextCard(self) -> None:
        self.previous_card = self.card
        self.card = None
        self._v3 = None

        if self.mw.col.sched.version < 3:
            self._get_next_v1_v2_card()
        else:
            self._get_next_v3_card()

        self._previous_card_info.set_card(self.previous_card)
        self._card_info.set_card(self.card)

        if not self.card:
            self.mw.moveToState("overview")
            return

        if self._reps is None or self._reps % 100 == 0:
            # we recycle the webview periodically so webkit can free memory
            self._initWeb()

        self._showQuestion()

    def _get_next_v1_v2_card(self) -> None:
        if self.cardQueue:
            # undone/edited cards to show
            card = self.cardQueue.pop()
            card.start_timer()
            self.hadCardQueue = True
        else:
            if self.hadCardQueue:
                # the undone/edited cards may be sitting in the regular queue;
                # need to reset
                self.mw.col.reset()
                self.hadCardQueue = False
            card = self.mw.col.sched.getCard()
        self.card = card

    def _get_next_v3_card(self) -> None:
        assert isinstance(self.mw.col.sched, V3Scheduler)
        output = self.mw.col.sched.get_queued_cards()
        if not output.cards:
            return
        self._v3 = V3CardInfo.from_queue(output)
        self.card = Card(self.mw.col, backend_card=self._v3.top_card().card)
        self.card.start_timer()

    def get_next_states(self) -> NextStates | None:
        if v3 := self._v3:
            return v3.next_states
        else:
Exemplo n.º 23
0
 def _rescheduleGraduatingLapse(self, card: Card, early: bool = False) -> None:
     if early:
         card.ivl += 1
     card.due = self.today + card.ivl
     card.queue = QUEUE_TYPE_REV
     card.type = CARD_TYPE_REV
Exemplo n.º 24
0
Arquivo: v1.py Projeto: njhsi/anki
 def _answerLrnCard(self, card: Card, ease: int) -> None:
     # ease 1=no, 2=yes, 3=remove
     conf = self._lrnConf(card)
     if card.odid and not card.wasNew:  # type: ignore
         type = REVLOG_CRAM
     elif card.type == CARD_TYPE_REV:
         type = REVLOG_RELRN
     else:
         type = REVLOG_LRN
     leaving = False
     # lrnCount was decremented once when card was fetched
     lastLeft = card.left
     # immediate graduate?
     if ease == BUTTON_THREE:
         self._rescheduleAsRev(card, conf, True)
         leaving = True
     # graduation time?
     elif ease == BUTTON_TWO and (card.left % 1000) - 1 <= 0:
         self._rescheduleAsRev(card, conf, False)
         leaving = True
     else:
         # one step towards graduation
         if ease == BUTTON_TWO:
             # decrement real left count and recalculate left today
             left = (card.left % 1000) - 1
             card.left = self._leftToday(conf["delays"], left) * 1000 + left
         # failed
         else:
             card.left = self._startingLeft(card)
             resched = self._resched(card)
             if "mult" in conf and resched:
                 # review that's lapsed
                 card.ivl = max(1, conf["minInt"], int(card.ivl * conf["mult"]))
             else:
                 # new card; no ivl adjustment
                 pass
             if resched and card.odid:
                 card.odue = self.today + 1
         delay = self._delayForGrade(conf, card.left)
         if card.due < time.time():
             # not collapsed; add some randomness
             delay *= int(random.uniform(1, 1.25))
         card.due = int(time.time() + delay)
         # due today?
         if card.due < self.dayCutoff:
             self.lrnCount += card.left // 1000
             # 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
             # it twice in a row
             card.queue = QUEUE_TYPE_LRN
             if self._lrnQueue and not self.revCount and not self.newCount:
                 smallestDue = self._lrnQueue[0][0]
                 card.due = max(card.due, smallestDue + 1)
             heappush(self._lrnQueue, (card.due, card.id))
         else:
             # the card is due in one or more days, so we need to use the
             # day learn queue
             ahead = ((card.due - self.dayCutoff) // 86400) + 1
             card.due = self.today + ahead
             card.queue = QUEUE_TYPE_DAY_LEARN_RELEARN
     self._logLrn(card, ease, conf, leaving, type, lastLeft)
Exemplo n.º 25
0
def maybe_get_setting_from_card(card) -> Optional[ScriptSetting]:
    the_note = Card(mw.col, card.id).note()
    maybe_model = the_note.model()

    return get_setting_from_notetype(maybe_model) if maybe_model else None
Exemplo n.º 26
0
Arquivo: v1.py Projeto: njhsi/anki
 def _rescheduleNew(self, card: Card, conf: QueueConfig, early: bool) -> None:
     "Reschedule a new card that's graduated for the first time."
     card.ivl = self._graduatingIvl(card, conf, early)
     card.due = self.today + card.ivl
     card.factor = conf["initialFactor"]
Exemplo n.º 27
0
 def getCard(self, id: int) -> Card:
     return Card(self, id)
Exemplo n.º 28
0
Arquivo: v1.py Projeto: njhsi/anki
 def _rescheduleLapse(self, card: Card) -> int:
     conf = self._lapseConf(card)
     card.lastIvl = card.ivl
     if self._resched(card):
         card.lapses += 1
         card.ivl = self._nextLapseIvl(card, conf)
         card.factor = max(1300, card.factor - 200)
         card.due = self.today + card.ivl
         # if it's a filtered deck, update odue as well
         if card.odid:
             card.odue = card.due
     # if suspended as a leech, nothing to do
     delay: int = 0
     if self._checkLeech(card, conf) and card.queue == QUEUE_TYPE_SUSPENDED:
         return delay
     # if no relearning steps, nothing to do
     if not conf["delays"]:
         return delay
     # record rev due date for later
     if not card.odue:
         card.odue = card.due
     delay = self._delayForGrade(conf, 0)
     card.due = int(delay + time.time())
     card.left = self._startingLeft(card)
     # queue 1
     if card.due < self.dayCutoff:
         self.lrnCount += card.left // 1000
         card.queue = QUEUE_TYPE_LRN
         heappush(self._lrnQueue, (card.due, card.id))
     else:
         # day learn queue
         ahead = ((card.due - self.dayCutoff) // 86400) + 1
         card.due = self.today + ahead
         card.queue = QUEUE_TYPE_DAY_LEARN_RELEARN
     return delay
Exemplo n.º 29
0
 def _updateRevIvlOnFail(self, card: Card, conf: QueueConfig) -> None:
     card.lastIvl = card.ivl
     card.ivl = self._lapseIvl(card, conf)
Exemplo n.º 30
0
    def _moveToNextStep(self, card: Card, conf: QueueConfig) -> None:
        # decrement real left count and recalculate left today
        left = (card.left % 1000) - 1
        card.left = self._leftToday(conf["delays"], left) * 1000 + left

        self._rescheduleLrnCard(card, conf)
Exemplo n.º 31
0
def prepare(html, card, context: str):
    if settings.enabled is False:
        return html
    if card.note_type()['name'] != settings.note_type:
        return html
    if mw is None:
        return html

    sched = copy.copy(mw.col.sched)

    for attr, value in vars(sched).items():
        try:
            setattr(sched, attr, copy.deepcopy(value))
        except Exception:
            pass

    next_card = None

    if sched.version == 3:
        sched_v3 = sched  # type: Any
        cards = sched_v3.get_queued_cards(fetch_limit=2)
        if len(cards.cards) > 1:
            queued_card = cards.cards[1]

            if queued_card is not None:
                next_card = Card(sched.col)
                next_card._load_from_backend_card(queued_card.card)
                next_card.load()
    else:
        next_card = sched.getCard()

    if next_card is not None and settings.question_field is not None:
        try:
            next_term = next_card.note()[
                settings.question_field]  # type: Optional[str]
        except KeyError:
            next_term = next_card.note().values()[0]
    else:
        next_term = None

    next_id = None

    if next_card:
        next_id = next_card.note().id

    if context.startswith("clayout"):
        # in card layout preview we don't have current note, but we can use next_term
        current_term = "malli" if next_term is None else next_term
        current_id = next_id if next_id is not None else -1
    else:
        current_id = card.note().id

        try:
            current_term = card.note()[settings.question_field]
        except KeyError:
            current_term = card.note().values()[0]

    card_types = {
        0: "Forwards",
        1: "Reversed",
    }

    app_dict = {
        'context': context,
        'isAnki': True,
        'currentTerm': current_term,
        'cardType': card_types.get(card.ord, "Unknown"),
        'tags': card.note().tags,
        'id': current_id,
        'nextTerm': next_term,
        'nextId': next_id,
    }
    return f"""
<script>
window.myAnkiSetup = {dumps(app_dict)};
if (window.myAnkiUpdate) window.myAnkiUpdate(window.myAnkiSetup);
</script>""" + html