anki/qt/aqt/update.py
Damien Elmes ffd392de21
Change Anki's version scheme; bump to 23.09 (#2640)
* Accept iterables as inputs to backend methods

* Shift add-on check to backend; use new endpoint

The new endpoint will return info on a suitable branch if found,
instead of returning all branches. This simplifies the frontend code,
and means that you can now drop support for certain versions without
it also remotely disabling the add-on for people who are running one of
the excluded versions, like in

https://forums.ankiweb.net/t/prevent-add-ons-from-being-disabled-remote-stealthily-surreptitiously/33427

* Bump version to 23.09

This changes Anki's version numbering system to year.month.patch, as
previously mentioned on https://forums.ankiweb.net/t/use-a-different-versioning-system-semver-perhaps/20046/5

This is shaping up to be a big release, with the introduction of FSRS and
image occlusion, and it seems like a good time to be finally updating the
version scheme as well. AnkiWeb has been updated to understand the new
format, and add-on authors will now specify version compatibility using
the full version number, as can be seen here:

https://ankiweb.net/shared/info/3918629684

* Shift update check to backend, and tidy up update.py

* Use the shared client for sync connections too
2023-09-07 12:37:15 +10:00

76 lines
2.5 KiB
Python

# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import aqt
from anki.buildinfo import buildhash
from anki.collection import CheckForUpdateResponse, Collection
from anki.utils import dev_mode, int_time, int_version, plat_desc
from aqt.operations import QueryOp
from aqt.qt import *
from aqt.utils import openLink, show_warning, showText, tr
def check_for_update() -> None:
from aqt import mw
def do_check(_col: Collection) -> CheckForUpdateResponse:
return mw.backend.check_for_update(
version=int_version(),
buildhash=buildhash,
os=plat_desc(),
install_id=mw.pm.meta["id"],
last_message_id=max(0, mw.pm.meta["lastMsg"]),
)
def on_done(resp: CheckForUpdateResponse) -> None:
# is clock off?
if not dev_mode:
diff = abs(resp.current_time - int_time())
if diff > 300:
diff_text = tr.qt_misc_second(count=diff)
warn = (
tr.qt_misc_in_order_to_ensure_your_collection(val="%s") % diff_text
)
show_warning(warn)
mw.app.closeAllWindows()
return
# should we show a message?
if msg := resp.message:
showText(msg, parent=mw, type="html")
mw.pm.meta["lastMsg"] = resp.last_message_id
# has Anki been updated?
if ver := resp.new_version:
prompt_to_update(mw, ver)
def on_fail(exc: Exception) -> None:
print(f"update check failed: {exc}")
QueryOp(parent=mw, op=do_check, success=on_done).failure(
on_fail
).run_in_background()
def prompt_to_update(mw: aqt.AnkiQt, ver: str) -> None:
msg = (
tr.qt_misc_anki_updatedanki_has_been_released(val=ver)
+ tr.qt_misc_would_you_like_to_download_it()
)
msgbox = QMessageBox(mw)
msgbox.setStandardButtons(
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
msgbox.setIcon(QMessageBox.Icon.Information)
msgbox.setText(msg)
button = QPushButton(tr.qt_misc_ignore_this_update())
msgbox.addButton(button, QMessageBox.ButtonRole.RejectRole)
msgbox.setDefaultButton(QMessageBox.StandardButton.Yes)
ret = msgbox.exec()
if msgbox.clickedButton() == button:
# ignore this update
mw.pm.meta["suppressUpdate"] = ver
elif ret == QMessageBox.StandardButton.Yes:
openLink(aqt.appWebsiteDownloadSection)