2019-02-05 04:59:03 +01:00
|
|
|
# Copyright: Ankitects Pty Ltd and contributors
|
2012-12-21 08:51:59 +01:00
|
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
2021-02-01 13:08:56 +01:00
|
|
|
|
2022-05-20 09:13:46 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2022-03-10 07:06:55 +01:00
|
|
|
from typing import Tuple
|
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
import aqt
|
2022-02-13 04:40:47 +01:00
|
|
|
import aqt.forms
|
|
|
|
import aqt.operations
|
2022-03-10 07:06:55 +01:00
|
|
|
from anki.collection import Collection
|
2012-12-21 08:51:59 +01:00
|
|
|
from anki.consts import *
|
2022-03-10 07:06:55 +01:00
|
|
|
from anki.decks import DeckId
|
2022-01-20 05:25:22 +01:00
|
|
|
from anki.scheduler import CustomStudyRequest
|
2022-03-10 07:06:55 +01:00
|
|
|
from anki.scheduler.base import CustomStudyDefaults
|
|
|
|
from aqt.operations import QueryOp
|
2022-01-20 05:25:22 +01:00
|
|
|
from aqt.operations.scheduling import custom_study
|
2019-12-20 10:19:03 +01:00
|
|
|
from aqt.qt import *
|
2022-01-20 05:25:22 +01:00
|
|
|
from aqt.taglimit import TagLimit
|
|
|
|
from aqt.utils import disable_help_button, tr
|
2012-12-21 08:51:59 +01:00
|
|
|
|
|
|
|
RADIO_NEW = 1
|
|
|
|
RADIO_REV = 2
|
|
|
|
RADIO_FORGOT = 3
|
|
|
|
RADIO_AHEAD = 4
|
2013-05-27 06:50:01 +02:00
|
|
|
RADIO_PREVIEW = 5
|
|
|
|
RADIO_CRAM = 6
|
|
|
|
|
|
|
|
TYPE_NEW = 0
|
|
|
|
TYPE_DUE = 1
|
2018-07-11 12:35:08 +02:00
|
|
|
TYPE_REVIEW = 2
|
|
|
|
TYPE_ALL = 3
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2019-12-23 01:34:10 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
class CustomStudy(QDialog):
|
2022-03-10 07:06:55 +01:00
|
|
|
@staticmethod
|
|
|
|
def fetch_data_and_show(mw: aqt.AnkiQt) -> None:
|
|
|
|
def fetch_data(
|
|
|
|
col: Collection,
|
|
|
|
) -> Tuple[DeckId, CustomStudyDefaults]:
|
|
|
|
deck_id = mw.col.decks.get_current_id()
|
|
|
|
defaults = col.sched.custom_study_defaults(deck_id)
|
|
|
|
return (deck_id, defaults)
|
|
|
|
|
|
|
|
def show_dialog(data: Tuple[DeckId, CustomStudyDefaults]) -> None:
|
|
|
|
deck_id, defaults = data
|
|
|
|
CustomStudy(mw=mw, deck_id=deck_id, defaults=defaults)
|
|
|
|
|
|
|
|
QueryOp(
|
|
|
|
parent=mw, op=fetch_data, success=show_dialog
|
|
|
|
).with_progress().run_in_background()
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
mw: aqt.AnkiQt,
|
|
|
|
deck_id: DeckId,
|
|
|
|
defaults: CustomStudyDefaults,
|
|
|
|
) -> None:
|
|
|
|
"Don't call this directly; use CustomStudy.fetch_data_and_show()."
|
2012-12-21 08:51:59 +01:00
|
|
|
QDialog.__init__(self, mw)
|
|
|
|
self.mw = mw
|
2022-03-10 07:06:55 +01:00
|
|
|
self.deck_id = deck_id
|
|
|
|
self.defaults = defaults
|
|
|
|
self.form = aqt.forms.customstudy.Ui_Dialog()
|
|
|
|
self.form.setupUi(self)
|
2021-01-07 05:24:49 +01:00
|
|
|
disable_help_button(self)
|
2012-12-21 08:51:59 +01:00
|
|
|
self.setupSignals()
|
2022-03-10 07:06:55 +01:00
|
|
|
self.form.radioNew.click()
|
2022-02-10 00:53:13 +01:00
|
|
|
self.open()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def setupSignals(self) -> None:
|
2016-05-31 10:51:40 +02:00
|
|
|
f = self.form
|
2020-05-04 05:23:08 +02:00
|
|
|
qconnect(f.radioNew.clicked, lambda: self.onRadioChange(RADIO_NEW))
|
|
|
|
qconnect(f.radioRev.clicked, lambda: self.onRadioChange(RADIO_REV))
|
|
|
|
qconnect(f.radioForgot.clicked, lambda: self.onRadioChange(RADIO_FORGOT))
|
|
|
|
qconnect(f.radioAhead.clicked, lambda: self.onRadioChange(RADIO_AHEAD))
|
|
|
|
qconnect(f.radioPreview.clicked, lambda: self.onRadioChange(RADIO_PREVIEW))
|
|
|
|
qconnect(f.radioCram.clicked, lambda: self.onRadioChange(RADIO_CRAM))
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2022-05-20 09:13:46 +02:00
|
|
|
def count_with_children(self, parent: int, children: int) -> str:
|
|
|
|
if children:
|
|
|
|
return f"{parent} {tr.custom_study_available_child_count(children)}"
|
|
|
|
else:
|
|
|
|
return str(parent)
|
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def onRadioChange(self, idx: int) -> None:
|
2022-03-10 07:06:55 +01:00
|
|
|
form = self.form
|
|
|
|
min_spinner_value = 1
|
|
|
|
max_spinner_value = DYN_MAX_SIZE
|
|
|
|
current_spinner_value = 1
|
|
|
|
text_after_spinner = tr.custom_study_cards()
|
|
|
|
title_text = ""
|
|
|
|
show_cram_type = False
|
2021-03-26 04:48:26 +01:00
|
|
|
ok = tr.custom_study_ok()
|
2019-12-23 01:34:10 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
if idx == RADIO_NEW:
|
2022-05-20 09:13:46 +02:00
|
|
|
title_text = tr.custom_study_available_new_cards_2(
|
|
|
|
count_string=self.count_with_children(
|
|
|
|
self.defaults.available_new,
|
|
|
|
self.defaults.available_new_in_children,
|
|
|
|
),
|
2019-12-23 01:34:10 +01:00
|
|
|
)
|
2022-03-10 07:06:55 +01:00
|
|
|
text_before_spinner = tr.custom_study_increase_todays_new_card_limit_by()
|
|
|
|
current_spinner_value = self.defaults.extend_new
|
|
|
|
min_spinner_value = -DYN_MAX_SIZE
|
2012-12-21 08:51:59 +01:00
|
|
|
elif idx == RADIO_REV:
|
2022-05-20 09:13:46 +02:00
|
|
|
title_text = tr.custom_study_available_review_cards_2(
|
|
|
|
count_string=self.count_with_children(
|
|
|
|
self.defaults.available_review,
|
|
|
|
self.defaults.available_review_in_children,
|
|
|
|
),
|
2019-12-23 01:34:10 +01:00
|
|
|
)
|
2022-03-10 07:06:55 +01:00
|
|
|
text_before_spinner = tr.custom_study_increase_todays_review_limit_by()
|
|
|
|
current_spinner_value = self.defaults.extend_review
|
|
|
|
min_spinner_value = -DYN_MAX_SIZE
|
2012-12-21 08:51:59 +01:00
|
|
|
elif idx == RADIO_FORGOT:
|
2022-03-10 07:06:55 +01:00
|
|
|
text_before_spinner = tr.custom_study_review_cards_forgotten_in_last()
|
|
|
|
text_after_spinner = tr.scheduling_days()
|
|
|
|
max_spinner_value = 30
|
2012-12-21 08:51:59 +01:00
|
|
|
elif idx == RADIO_AHEAD:
|
2022-03-10 07:06:55 +01:00
|
|
|
text_before_spinner = tr.custom_study_review_ahead_by()
|
|
|
|
text_after_spinner = tr.scheduling_days()
|
2012-12-21 08:51:59 +01:00
|
|
|
elif idx == RADIO_PREVIEW:
|
2022-03-10 07:06:55 +01:00
|
|
|
text_before_spinner = tr.custom_study_preview_new_cards_added_in_the()
|
|
|
|
text_after_spinner = tr.scheduling_days()
|
|
|
|
current_spinner_value = 1
|
2013-05-27 06:50:01 +02:00
|
|
|
elif idx == RADIO_CRAM:
|
2022-03-10 07:06:55 +01:00
|
|
|
text_before_spinner = tr.custom_study_select()
|
|
|
|
text_after_spinner = tr.custom_study_cards_from_the_deck()
|
2021-03-26 04:48:26 +01:00
|
|
|
ok = tr.custom_study_choose_tags()
|
2022-03-10 07:06:55 +01:00
|
|
|
current_spinner_value = 100
|
|
|
|
show_cram_type = True
|
|
|
|
|
|
|
|
form.spin.setVisible(True)
|
|
|
|
form.cardType.setVisible(show_cram_type)
|
|
|
|
form.title.setText(title_text)
|
|
|
|
form.title.setVisible(not not title_text)
|
|
|
|
form.spin.setMinimum(min_spinner_value)
|
|
|
|
form.spin.setMaximum(max_spinner_value)
|
|
|
|
if max_spinner_value > 0:
|
|
|
|
form.spin.setEnabled(True)
|
2020-04-10 10:26:49 +02:00
|
|
|
else:
|
2022-03-10 07:06:55 +01:00
|
|
|
form.spin.setEnabled(False)
|
|
|
|
form.spin.setValue(current_spinner_value)
|
|
|
|
form.preSpin.setText(text_before_spinner)
|
|
|
|
form.postSpin.setText(text_after_spinner)
|
|
|
|
form.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(ok)
|
2012-12-21 08:51:59 +01:00
|
|
|
self.radioIdx = idx
|
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def accept(self) -> None:
|
2022-03-10 07:06:55 +01:00
|
|
|
request = CustomStudyRequest(deck_id=self.deck_id)
|
2022-01-20 05:25:22 +01:00
|
|
|
if self.radioIdx == RADIO_NEW:
|
|
|
|
request.new_limit_delta = self.form.spin.value()
|
|
|
|
elif self.radioIdx == RADIO_REV:
|
|
|
|
request.review_limit_delta = self.form.spin.value()
|
|
|
|
elif self.radioIdx == RADIO_FORGOT:
|
|
|
|
request.forgot_days = self.form.spin.value()
|
|
|
|
elif self.radioIdx == RADIO_AHEAD:
|
|
|
|
request.review_ahead_days = self.form.spin.value()
|
|
|
|
elif self.radioIdx == RADIO_PREVIEW:
|
|
|
|
request.preview_days = self.form.spin.value()
|
2012-12-21 08:51:59 +01:00
|
|
|
else:
|
2022-01-20 05:25:22 +01:00
|
|
|
request.cram.card_limit = self.form.spin.value()
|
|
|
|
|
|
|
|
cram_type = self.form.cardType.currentRow()
|
|
|
|
if cram_type == TYPE_NEW:
|
|
|
|
request.cram.kind = CustomStudyRequest.Cram.CRAM_KIND_NEW
|
|
|
|
elif cram_type == TYPE_DUE:
|
|
|
|
request.cram.kind = CustomStudyRequest.Cram.CRAM_KIND_DUE
|
|
|
|
elif cram_type == TYPE_REVIEW:
|
|
|
|
request.cram.kind = CustomStudyRequest.Cram.CRAM_KIND_REVIEW
|
2013-05-27 06:50:01 +02:00
|
|
|
else:
|
2022-01-20 05:25:22 +01:00
|
|
|
request.cram.kind = CustomStudyRequest.Cram.CRAM_KIND_ALL
|
|
|
|
|
2022-03-10 07:06:55 +01:00
|
|
|
def on_done(include: list[str], exclude: list[str]) -> None:
|
|
|
|
request.cram.tags_to_include.extend(include)
|
|
|
|
request.cram.tags_to_exclude.extend(exclude)
|
|
|
|
self._create_and_close(request)
|
|
|
|
|
|
|
|
# continues in background
|
|
|
|
TagLimit(self, self.defaults.tags, on_done)
|
|
|
|
return
|
|
|
|
|
|
|
|
# other cases are synchronous
|
|
|
|
self._create_and_close(request)
|
|
|
|
|
|
|
|
def _create_and_close(self, request: CustomStudyRequest) -> None:
|
2022-01-20 05:25:22 +01:00
|
|
|
# keep open on failure, as the cause was most likely an empty search
|
|
|
|
# result, which the user can remedy
|
|
|
|
custom_study(parent=self, request=request).success(
|
|
|
|
lambda _: QDialog.accept(self)
|
|
|
|
).run_in_background()
|