Beispiel #1
0
 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: Literal["question", "answer", "transition", 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)
Beispiel #2
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: Literal["question", "answer", "transition", 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:
        if self.mw.col.sched_ver() == 1:
            self.mw.moveToState("deckBrowser")
            return
        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.get_card(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
        elif self._refresh_needed is RefreshNeeded.FLAG:
            self.card.load()
            self._update_flag_icon()
            # for when modified in browser
            self.mw.fade_in_webview()
            self._refresh_needed = None
        elif self._refresh_needed:
            assert_exhaustive(self._refresh_needed)

    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
            elif changes.card:
                self._refresh_needed = RefreshNeeded.FLAG

        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: