Merge branch 'main' into apkg

This commit is contained in:
RumovZ 2022-04-22 08:39:10 +02:00
commit 4837e52fe9
10 changed files with 43 additions and 31 deletions

View file

@ -370,7 +370,6 @@ class AnkiPackageExporter(AnkiExporter):
p = path.replace(".apkg", ".media.db2") p = path.replace(".apkg", ".media.db2")
if os.path.exists(p): if os.path.exists(p):
os.unlink(p) os.unlink(p)
os.chdir(self.mediaDir)
shutil.rmtree(path.replace(".apkg", ".media")) shutil.rmtree(path.replace(".apkg", ".media"))
return media return media

View file

@ -309,13 +309,15 @@ class DataModel(QAbstractTableModel):
return 0 return 0
return self.len_columns() return self.len_columns()
_QFont = without_qt5_compat_wrapper(QFont)
def data(self, index: QModelIndex = QModelIndex(), role: int = 0) -> Any: def data(self, index: QModelIndex = QModelIndex(), role: int = 0) -> Any:
if not index.isValid(): if not index.isValid():
return QVariant() return QVariant()
if role == Qt.ItemDataRole.FontRole: if role == Qt.ItemDataRole.FontRole:
if not self.column_at(index).uses_cell_font: if not self.column_at(index).uses_cell_font:
return QVariant() return QVariant()
qfont = QFont() qfont = self._QFont()
row = self.get_row(index) row = self.get_row(index)
qfont.setFamily(row.font_name) qfont.setFamily(row.font_name)
qfont.setPixelSize(row.font_size) qfont.setPixelSize(row.font_size)

View file

@ -758,7 +758,9 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
def urlToLink(self, url: str) -> str | None: def urlToLink(self, url: str) -> str | None:
fname = self.urlToFile(url) fname = self.urlToFile(url)
if not fname: if not fname:
return None return '<a href="{}">{}</a>'.format(
url, html.escape(urllib.parse.unquote(url))
)
return self.fnameToLink(fname) return self.fnameToLink(fname)
def fnameToLink(self, fname: str) -> str: def fnameToLink(self, fname: str) -> str:
@ -1261,7 +1263,7 @@ class EditorWebView(AnkiWebView):
url = qurl.toString() url = qurl.toString()
# chrome likes to give us the URL twice with a \n # chrome likes to give us the URL twice with a \n
url = url.splitlines()[0] url = url.splitlines()[0]
buf += self.editor.urlToLink(url) or "" buf += self.editor.urlToLink(url)
return buf return buf
@ -1279,15 +1281,8 @@ class EditorWebView(AnkiWebView):
if extended and token.startswith("data:image/"): if extended and token.startswith("data:image/"):
processed.append(self.editor.inlinedImageToLink(token)) processed.append(self.editor.inlinedImageToLink(token))
elif extended and self.editor.isURL(token): elif extended and self.editor.isURL(token):
# if the user is pasting an image or sound link, convert it to local # if the user is pasting an image or sound link, convert it to local, otherwise paste as a hyperlink
link = self.editor.urlToLink(token) link = self.editor.urlToLink(token)
if link:
processed.append(link)
else:
# not media; add it as a normal link
link = '<a href="{}">{}</a>'.format(
token, html.escape(urllib.parse.unquote(token))
)
processed.append(link) processed.append(link)
else: else:
token = html.escape(token).replace("\t", " " * 4) token = html.escape(token).replace("\t", " " * 4)

View file

@ -14,7 +14,7 @@ import aqt.modelchooser
from anki.errors import Interrupted from anki.errors import Interrupted
from anki.importing.anki2 import V2ImportIntoV1 from anki.importing.anki2 import V2ImportIntoV1
from anki.importing.apkg import AnkiPackageImporter from anki.importing.apkg import AnkiPackageImporter
from aqt import AnkiQt, gui_hooks from aqt.main import AnkiQt, gui_hooks
from aqt.operations import QueryOp from aqt.operations import QueryOp
from aqt.qt import * from aqt.qt import *
from aqt.utils import ( from aqt.utils import (
@ -460,12 +460,13 @@ def full_apkg_import(mw: AnkiQt, file: str) -> None:
def replace_with_apkg( def replace_with_apkg(
mw: aqt.AnkiQt, filename: str, callback: Callable[[bool], None] mw: AnkiQt, filename: str, callback: Callable[[bool], None]
) -> None: ) -> None:
"""Tries to replace the provided collection with the provided backup, """Tries to replace the provided collection with the provided backup,
then calls the callback. True if success. then calls the callback. True if success.
""" """
dialog = mw.progress.start(immediate=True) if not (dialog := mw.progress.start(immediate=True)):
print("No progress dialog during import; aborting will not work")
timer = QTimer() timer = QTimer()
timer.setSingleShot(False) timer.setSingleShot(False)
timer.setInterval(100) timer.setInterval(100)

View file

@ -217,6 +217,10 @@ class QueryOp(Generic[T]):
def wrapped_done(future: Future) -> None: def wrapped_done(future: Future) -> None:
assert mw assert mw
if self._progress:
mw.progress.finish()
mw._decrease_background_ops() mw._decrease_background_ops()
# did something go wrong? # did something go wrong?
if exception := future.exception(): if exception := future.exception():
@ -230,11 +234,6 @@ class QueryOp(Generic[T]):
# BaseException like SystemExit; rethrow it # BaseException like SystemExit; rethrow it
future.result() future.result()
result = future.result() self._success(future.result())
try:
self._success(result)
finally:
if self._progress:
mw.progress.finish()
mw.taskman.run_in_background(wrapped_op, wrapped_done) mw.taskman.run_in_background(wrapped_op, wrapped_done)

View file

@ -7,7 +7,7 @@
import os import os
import sys import sys
import traceback import traceback
from typing import Callable, Union from typing import Callable, TypeVar, Union
try: try:
import PyQt6 import PyQt6
@ -58,3 +58,16 @@ def qconnect(
) -> None: ) -> None:
"""Helper to work around type checking not working with signal.connect(func).""" """Helper to work around type checking not working with signal.connect(func)."""
signal.connect(func) # type: ignore signal.connect(func) # type: ignore
_T = TypeVar("_T")
def without_qt5_compat_wrapper(cls: _T) -> _T:
"""Remove Qt5 compat wrapper from Qt class, if active.
Only needed for a few Qt APIs that deal with QVariants."""
if fn := getattr(cls, "_without_compat_wrapper", None):
return fn()
else:
return cls

View file

@ -352,7 +352,9 @@ def _instrument_type(
class QtClassProxy( class QtClassProxy(
type, metaclass=QtClassProxyType type, metaclass=QtClassProxyType
): # pylint: disable=invalid-metaclass ): # pylint: disable=invalid-metaclass
pass @staticmethod
def _without_compat_wrapper():
return type
setattr(module, type_name, QtClassProxy) setattr(module, type_name, QtClassProxy)

View file

@ -330,6 +330,7 @@ class AnkiWebView(QWebEngineView):
self._domDone = True self._domDone = True
self._queueAction("setHtml", html) self._queueAction("setHtml", html)
self.set_open_links_externally(True) self.set_open_links_externally(True)
self.setZoomFactor(1)
self.show() self.show()
def _setHtml(self, html: str) -> None: def _setHtml(self, html: str) -> None:
@ -681,6 +682,7 @@ html {{ {font} }}
else: else:
extra = "" extra = ""
self.hide_while_preserving_layout() self.hide_while_preserving_layout()
self.setZoomFactor(1)
self.load_url(QUrl(f"{mw.serverURL()}_anki/pages/{name}.html{extra}")) self.load_url(QUrl(f"{mw.serverURL()}_anki/pages/{name}.html{extra}"))
self.inject_dynamic_style_and_show() self.inject_dynamic_style_and_show()

View file

@ -343,13 +343,13 @@ def build_tarball(src_path: Path, variant: str) -> None:
subprocess.run( subprocess.run(
[ [
"tar", "tar",
"--zstd", "-I",
"zstd -c --long -T0 -18",
"-cf", "-cf",
dist_folder / (dest_path.name + ".tar.zst"), dist_folder / (dest_path.name + ".tar.zst"),
dest_path.name, dest_path.name,
], ],
check=True, check=True,
env=dict(ZSTD_CLEVEL="9"),
cwd=dest_path.parent, cwd=dest_path.parent,
) )

View file

@ -23,6 +23,10 @@ img {
max-height: 95vh; max-height: 95vh;
} }
li {
text-align: start;
}
#_flag { #_flag {
position: fixed; position: fixed;
right: 10px; right: 10px;
@ -48,11 +52,6 @@ img {
box-sizing: border-box; box-sizing: border-box;
} }
.night-mode #typeans {
background-color: var(--frame-bg);
color: var(--text-fg);
}
.typeGood { .typeGood {
background: #afa; background: #afa;
color: black; color: black;