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)
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: