diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 7ab875ba727..4bccef3057b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -32,8 +32,8 @@ AMBOSS MD Inc.
Aristotelis P.
Erez Volk
zjosua
-Arthur Milchior
Yngve Hoiseth
+Arthur Milchior
Ijgnd
Yoonchae Lee
Evandro Coan
diff --git a/proto/anki/frontend.proto b/proto/anki/frontend.proto
index 7c69429ab69..95b929c5ca5 100644
--- a/proto/anki/frontend.proto
+++ b/proto/anki/frontend.proto
@@ -22,6 +22,11 @@ service FrontendService {
rpc ImportDone(generic.Empty) returns (generic.Empty);
rpc SearchInBrowser(search.SearchNode) returns (generic.Empty);
+
+ // Force closing the deck options.
+ rpc deckOptionsRequireClose(generic.Empty) returns (generic.Empty);
+ // Warns python that the deck option web view is ready to receive requests.
+ rpc deckOptionsReady(generic.Empty) returns (generic.Empty);
}
service BackendFrontendService {}
diff --git a/qt/aqt/deckoptions.py b/qt/aqt/deckoptions.py
index 9cc3d8e453a..9353da5246b 100644
--- a/qt/aqt/deckoptions.py
+++ b/qt/aqt/deckoptions.py
@@ -14,7 +14,6 @@
from aqt.utils import (
KeyboardModifiersPressed,
addCloseShortcut,
- ask_user_dialog,
disable_help_button,
restoreGeom,
saveGeom,
@@ -46,7 +45,6 @@ def _setup_ui(self) -> None:
addCloseShortcut(self)
self.web = AnkiWebView(kind=AnkiWebViewKind.DECK_OPTIONS)
- self.web.set_bridge_command(self._on_bridge_cmd, self)
self.web.load_sveltekit_page(f"deck-options/{self._deck['id']}")
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
@@ -58,43 +56,22 @@ def _setup_ui(self) -> None:
without_unicode_isolation(tr.actions_options_for(val=self._deck["name"]))
)
- def _on_bridge_cmd(self, cmd: str) -> None:
- if cmd == "deckOptionsReady":
- self._ready = True
- gui_hooks.deck_options_did_load(self)
- elif cmd == "confirmDiscardChanges":
- self.confirm_discard_changes()
- elif cmd == "_close":
- self._close()
+ def set_ready(self):
+ self._ready = True
+ gui_hooks.deck_options_did_load(self)
def closeEvent(self, evt: QCloseEvent | None) -> None:
- if self._close_event_has_cleaned_up:
+ if self._close_event_has_cleaned_up or not self._ready:
return super().closeEvent(evt)
assert evt is not None
evt.ignore()
- self.check_pending_changes()
+ self.web.eval("anki.deckOptionsPendingChanges();")
- def _close(self):
+ def require_close(self):
"""Close. Ensure the closeEvent is not ignored."""
self._close_event_has_cleaned_up = True
self.close()
- def confirm_discard_changes(self) -> None:
- def callbackWithUserChoice(choice: int) -> None:
- if choice == 0:
- # The user accepted to discard current input.
- self._close()
-
- ask_user_dialog(
- tr.card_templates_discard_changes(),
- callback=callbackWithUserChoice,
- buttons=[
- QMessageBox.StandardButton.Discard,
- (tr.adding_keep_editing(), QMessageBox.ButtonRole.RejectRole),
- ],
- parent=self,
- )
-
def reject(self) -> None:
self.mw.col.set_wants_abort()
self.web.cleanup()
@@ -102,12 +79,6 @@ def reject(self) -> None:
saveGeom(self, self.TITLE)
QDialog.reject(self)
- def check_pending_changes(self):
- if self._ready:
- self.web.eval("anki.deckOptionsPendingChanges();")
- else:
- self._close()
-
def confirm_deck_then_display_options(active_card: Card | None = None) -> None:
decks = [aqt.mw.col.decks.current()]
diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py
index 15d9a0fd12f..122b9a3a4fa 100644
--- a/qt/aqt/mediasrv.py
+++ b/qt/aqt/mediasrv.py
@@ -75,6 +75,7 @@ class PageContext(enum.IntEnum):
REVIEWER = enum.auto()
PREVIEWER = enum.auto()
CARD_LAYOUT = enum.auto()
+ DECK_OPTIONS = enum.auto()
# something in /_anki/pages/
NON_LEGACY_PAGE = enum.auto()
# Do not use this if you present user content (e.g. content from cards), as it's a
@@ -574,6 +575,26 @@ def handle_on_main() -> None:
return b""
+def deck_options_require_close() -> bytes:
+ def handle_on_main() -> None:
+ window = aqt.mw.app.activeWindow()
+ if isinstance(window, DeckOptionsDialog):
+ window.require_close()
+
+ aqt.mw.taskman.run_on_main(handle_on_main)
+ return b""
+
+
+def deck_options_ready() -> bytes:
+ def handle_on_main() -> None:
+ window = aqt.mw.app.activeWindow()
+ if isinstance(window, DeckOptionsDialog):
+ window.set_ready()
+
+ aqt.mw.taskman.run_on_main(handle_on_main)
+ return b""
+
+
post_handler_list = [
congrats_info,
get_deck_configs_for_update,
@@ -587,6 +608,8 @@ def handle_on_main() -> None:
import_json_file,
import_json_string,
search_in_browser,
+ deck_options_require_close,
+ deck_options_ready,
]
@@ -685,11 +708,12 @@ def warn() -> None:
aqt.mw.taskman.run_on_main(warn)
abort(403)
- if (
- context == PageContext.NON_LEGACY_PAGE
- or context == PageContext.EDITOR
- or context == PageContext.ADDON_PAGE
- ):
+ if context in [
+ PageContext.NON_LEGACY_PAGE,
+ PageContext.EDITOR,
+ PageContext.ADDON_PAGE,
+ PageContext.DECK_OPTIONS,
+ ]:
pass
elif context == PageContext.REVIEWER and request.path in (
"/_anki/getSchedulingStatesWithContext",
diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py
index 65d294bf6f2..980e7a989ec 100644
--- a/qt/aqt/webview.py
+++ b/qt/aqt/webview.py
@@ -611,6 +611,7 @@ def stdHtml(
# print(html)
import aqt.browser.previewer
import aqt.clayout
+ import aqt.deckoptions
import aqt.editor
import aqt.reviewer
from aqt.mediasrv import PageContext
@@ -623,6 +624,8 @@ def stdHtml(
page_context = PageContext.PREVIEWER
elif isinstance(context, aqt.clayout.CardLayout):
page_context = PageContext.CARD_LAYOUT
+ elif isinstance(context, aqt.deckoptions.DeckOptionsDialog):
+ page_context = PageContext.DECK_OPTIONS
else:
page_context = PageContext.UNKNOWN
self.setHtml(html, page_context)
diff --git a/ts/routes/deck-options/[deckId]/+page.svelte b/ts/routes/deck-options/[deckId]/+page.svelte
index c5064a9508e..08e056de56e 100644
--- a/ts/routes/deck-options/[deckId]/+page.svelte
+++ b/ts/routes/deck-options/[deckId]/+page.svelte
@@ -3,11 +3,13 @@ Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->