Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions build/configure/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,17 @@ fn build_and_check_pages(build: &mut Build) -> Result<()> {
":sveltekit"
],
)?;
build_page(
"reviewer-inner",
true,
inputs![
//
":ts:lib",
":ts:components",
":sass",
":sveltekit"
],
)?;

Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions ftl/core/preferences.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ preferences-on-next-sync-force-changes-in = On next sync, force changes in one d
preferences-paste-clipboard-images-as-png = Paste clipboard images as PNG
preferences-paste-without-shift-key-strips-formatting = Paste without shift key strips formatting
preferences-generate-latex-images-automatically = Generate LaTeX images (security risk)
preferences-use-new-reviewer = Use new reviewer
preferences-latex-generation-disabled = LaTeX image generation is disabled in the preferences.
preferences-periodically-sync-media = Periodically sync media
preferences-please-restart-anki-to-complete-language = Please restart Anki to complete language change.
Expand Down
13 changes: 13 additions & 0 deletions qt/aqt/forms/preferences.ui
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,19 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="new_reviewer">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>preferences_use_new_reviewer</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="url_schemes">
<property name="text">
Expand Down
15 changes: 9 additions & 6 deletions qt/aqt/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,11 @@ def setupUI(self) -> None:
# screens
self.setupDeckBrowser()
self.setupOverview()
self.setupReviewer()
# self.setupReviewer()

def finish_ui_setup(self) -> None:
"Actions that are deferred until after add-on loading."
self.toolbar.draw()
# add-ons are only available here after setupAddons
gui_hooks.reviewer_did_init(self.reviewer)

def setupProfileAfterWebviewsLoaded(self) -> None:
for w in (self.web, self.bottomWeb):
Expand Down Expand Up @@ -679,6 +677,8 @@ def loadCollection(self) -> bool:
# dump error to stderr so it gets picked up by errors.py
traceback.print_exc()

self.setupReviewer(self.backend.get_config_bool(Config.Bool.NEW_REVIEWER))

return True

def _loadCollection(self) -> None:
Expand Down Expand Up @@ -1079,10 +1079,13 @@ def setupOverview(self) -> None:

self.overview = Overview(self)

def setupReviewer(self) -> None:
from aqt.reviewer import Reviewer
def setupReviewer(self, new: bool) -> None:
from aqt.reviewer import Reviewer, SvelteReviewer

self.reviewer = Reviewer(self)
self.reviewer = SvelteReviewer(self) if new else Reviewer(self)

# add-ons are only available here after setupAddons
gui_hooks.reviewer_did_init(self.reviewer)

# Syncing
##########################################################################
Expand Down
2 changes: 2 additions & 0 deletions qt/aqt/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def setup_collection(self) -> None:
form.showProgress.setChecked(reviewing.show_remaining_due_counts)
form.showPlayButtons.setChecked(not reviewing.hide_audio_play_buttons)
form.interrupt_audio.setChecked(reviewing.interrupt_audio_when_answering)
form.new_reviewer.setChecked(reviewing.new_reviewer)

editing = self.prefs.editing
form.useCurrent.setCurrentIndex(
Expand Down Expand Up @@ -171,6 +172,7 @@ def update_collection(self, on_done: Callable[[], None]) -> None:
reviewing.time_limit_secs = form.timeLimit.value() * 60
reviewing.hide_audio_play_buttons = not self.form.showPlayButtons.isChecked()
reviewing.interrupt_audio_when_answering = self.form.interrupt_audio.isChecked()
reviewing.new_reviewer = form.new_reviewer.isChecked()

editing = self.prefs.editing
editing.adding_defaults_to_current_deck = not form.useCurrent.currentIndex()
Expand Down
24 changes: 22 additions & 2 deletions qt/aqt/webview.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
from enum import Enum
from typing import TYPE_CHECKING, Any, Type, cast

from google.protobuf.json_format import MessageToDict
from typing_extensions import TypedDict, Unpack

import anki
import anki.lang
from anki._legacy import deprecated
from anki.lang import is_rtl
from anki.utils import hmr_mode, is_lin, is_mac, is_win
from anki.utils import hmr_mode, is_lin, is_mac, is_win, to_json_bytes
from aqt import colors, gui_hooks
from aqt.operations import OpChanges
from aqt.qt import *
from aqt.qt import sip
from aqt.theme import theme_manager
Expand Down Expand Up @@ -131,6 +133,7 @@ def __init__(
self._kind = kind
self._setupBridge()
self.open_links_externally = True
self.open_iframe_links_externally = False

def _profileForPage(self, kind: AnkiWebViewKind) -> QWebEngineProfile:
have_api_access = kind in (
Expand All @@ -142,6 +145,7 @@ def _profileForPage(self, kind: AnkiWebViewKind) -> QWebEngineProfile:
AnkiWebViewKind.IMPORT_ANKI_PACKAGE,
AnkiWebViewKind.IMPORT_CSV,
AnkiWebViewKind.IMPORT_LOG,
AnkiWebViewKind.MAIN,
)

global _profile_with_api_access, _profile_without_api_access
Expand Down Expand Up @@ -252,7 +256,7 @@ def acceptNavigationRequest(
):
return super().acceptNavigationRequest(url, navType, isMainFrame)

if not isMainFrame:
if not self.open_iframe_links_externally and not isMainFrame:
return True
# data: links generated by setHtml()
if url.scheme() == "data":
Expand Down Expand Up @@ -382,6 +386,7 @@ def __init__(
self._filterSet = False
gui_hooks.theme_did_change.append(self.on_theme_did_change)
gui_hooks.body_classes_need_update.append(self.on_body_classes_need_update)
gui_hooks.operation_did_execute.append(self.on_operation_did_execute)

qconnect(self.loadFinished, self._on_load_finished)

Expand Down Expand Up @@ -437,6 +442,9 @@ def eventFilter(self, obj: QObject | None, evt: QEvent | None) -> bool:
def set_open_links_externally(self, enable: bool) -> None:
self.page().open_links_externally = enable

def set_open_iframe_links_externally(self, enable: bool) -> None:
self.page().open_iframe_links_externally = enable

def onEsc(self) -> None:
w = self.parent()
while w:
Expand Down Expand Up @@ -911,6 +919,7 @@ def cleanup(self) -> None:

gui_hooks.theme_did_change.remove(self.on_theme_did_change)
gui_hooks.body_classes_need_update.remove(self.on_body_classes_need_update)
gui_hooks.operation_did_execute.remove(self.on_operation_did_execute)
# defer page cleanup so that in-flight requests have a chance to complete first
# https://forums.ankiweb.net/t/error-when-exiting-browsing-when-the-software-is-installed-in-the-path-c-program-files-anki/38363
mw.progress.single_shot(5000, lambda: mw.mediaServer.clear_page_html(id(self)))
Expand Down Expand Up @@ -952,6 +961,17 @@ def on_body_classes_need_update(self) -> None:
f"""document.body.classList.toggle("reduce-motion", {json.dumps(mw.pm.reduce_motion())}); """
)

def on_operation_did_execute(
self, changes: OpChanges, handler: object | None
) -> None:
if handler is self.parentWidget():
return

changes_json = to_json_bytes(MessageToDict(changes)).decode()
self.eval(
f"if(globalThis.anki && globalThis.anki.onOperationDidExecute) globalThis.anki.onOperationDidExecute({changes_json})"
)

@deprecated(info="use theme_manager.qcolor() instead")
def get_window_bg_color(self, night_mode: bool | None = None) -> QColor:
return theme_manager.qcolor(colors.CANVAS)
Expand Down