Tweaks to add-on startup failure screen / update checks

- Add a Check for Updates button to the screen
- Make the update list screen non-modal, so that other modal pop-ups
at startup don't leave the user stuck
- When manually checking for updates, update Anki's last check time
This commit is contained in:
Damien Elmes 2023-10-26 09:22:59 +10:00
parent 9a027a8c48
commit 865296254a
3 changed files with 58 additions and 31 deletions

View file

@ -8,8 +8,10 @@ addons-failed-to-load2 =
The following add-ons failed to load:
{ $addons }
Use Tools>Add-ons to check for updates. For add-ons that don't have
an update available, you can disable or delete the add-on to prevent this
They may need to be updated to support this version of Anki. Click the { addons-check-for-updates } button
to see if any updates are available.
For add-ons that don't have an update available, you can disable or delete the add-on to prevent this
message from appearing.
addons-startup-failed = Add-on Startup Failed
# Shown in the add-on configuration screen (Tools>Add-ons>Config), in the title bar

View file

@ -256,18 +256,33 @@ class AddonManager:
)
txt = f"# {tr.addons_startup_failed()}\n{error}"
html2 = markdown.markdown(txt)
print(html2)
(diag, _) = showText(
box: QDialogButtonBox
(diag, box) = showText(
html2,
type="html",
copyBtn=True,
run=False,
)
but = box.addButton(
tr.addons_check_for_updates(), QDialogButtonBox.ButtonRole.ActionRole
)
but.clicked.connect(self.check_for_updates_after_load_failure)
from aqt import mw
# calling show immediately appears to crash
mw.progress.single_shot(1000, diag.show)
def check_for_updates_after_load_failure(self) -> None:
from aqt import mw
tooltip(tr.addons_checking())
def on_done(log: list[DownloadLogEntry]) -> None:
if not log:
tooltip(tr.addons_no_updates_available())
mw.check_for_addon_updates(by_user=True, on_done=on_done)
def onAddonsDialog(self) -> None:
aqt.dialogs.open("AddonsDialog", self)
@ -1326,12 +1341,14 @@ class ChooseAddonsToUpdateList(QListWidget):
class ChooseAddonsToUpdateDialog(QDialog):
_on_done: Callable[[list[int]], None]
def __init__(
self, parent: QWidget, mgr: AddonManager, updated_addons: list[AddonInfo]
) -> None:
QDialog.__init__(self, parent)
self.setWindowTitle(tr.addons_choose_update_window_title())
self.setWindowModality(Qt.WindowModality.WindowModal)
self.setWindowModality(Qt.WindowModality.NonModal)
self.mgr = mgr
self.updated_addons = updated_addons
self.setup()
@ -1358,15 +1375,15 @@ class ChooseAddonsToUpdateDialog(QDialog):
layout.addWidget(button_box)
self.setLayout(layout)
def ask(self) -> list[int]:
"Returns a list of selected addons' ids"
ret = self.exec()
def ask(self, on_done: Callable[[list[int]], None]) -> None:
self._on_done = on_done
self.show()
def accept(self) -> None:
saveGeom(self, "addonsChooseUpdate")
self.addons_list_widget.save_check_state()
if ret == QDialog.DialogCode.Accepted:
return self.addons_list_widget.get_selected_addon_ids()
else:
return []
self._on_done(self.addons_list_widget.get_selected_addon_ids())
QDialog.accept(self)
def fetch_update_info(ids: list[int]) -> list[AddonInfo]:
@ -1463,10 +1480,11 @@ def prompt_to_update(
if not prompt_update:
return
ids = ChooseAddonsToUpdateDialog(parent, mgr, updated_addons).ask()
if not ids:
return
download_addons(parent, mgr, ids, on_done, client)
def after_choosing(ids: list[int]) -> None:
if ids:
download_addons(parent, mgr, ids, on_done, client)
ChooseAddonsToUpdateDialog(parent, mgr, updated_addons).ask(after_choosing)
# Editing config

View file

@ -501,7 +501,7 @@ class AnkiQt(QMainWindow):
if onsuccess:
onsuccess()
if not self.safeMode:
self.maybe_check_for_addon_updates(self.setupAutoUpdate)
self.maybe_check_for_addon_updates(self.setup_auto_update)
self.maybe_auto_sync_on_open_close(_onsuccess)
@ -963,26 +963,33 @@ title="{}" {}>{}</button>""".format(
self.addonManager.loadAddons()
def maybe_check_for_addon_updates(
self, on_done: Callable[[], None] | None = None
self, on_done: Callable[[list[DownloadLogEntry]], None] | None = None
) -> None:
last_check = self.pm.last_addon_update_check()
elap = int_time() - last_check
if elap > 86_400 or self.pm.last_run_version != int_version():
self.check_for_addon_updates(by_user=False, on_done=on_done)
elif on_done:
on_done([])
def check_for_addon_updates(
self,
by_user: bool,
on_done: Callable[[list[DownloadLogEntry]], None] | None = None,
) -> None:
def wrap_on_updates_installed(log: list[DownloadLogEntry]) -> None:
self.on_updates_installed(log)
if on_done:
on_done()
if elap > 86_400 or self.pm.last_run_version != int_version():
check_and_prompt_for_updates(
self,
self.addonManager,
wrap_on_updates_installed,
requested_by_user=False,
)
self.pm.set_last_addon_update_check(int_time())
elif on_done:
on_done()
if on_done:
on_done(log)
check_and_prompt_for_updates(
self,
self.addonManager,
wrap_on_updates_installed,
requested_by_user=by_user,
)
def on_updates_installed(self, log: list[DownloadLogEntry]) -> None:
if log:
@ -1413,7 +1420,7 @@ title="{}" {}>{}</button>""".format(
# Auto update
##########################################################################
def setupAutoUpdate(self) -> None:
def setup_auto_update(self, _log: list[DownloadLogEntry]) -> None:
from aqt.update import check_for_update
check_for_update()