updater: Differentiate between "X" and "Cancel"

We want to differentiate between the user clicking on "Cancel" and
clicking on "X", since in the second case, we want to remind them again
on the next run.
This commit is contained in:
Alex Pyrgiotis 2023-07-25 16:11:21 +03:00
parent f6b5e1293d
commit 24ba914cc8
No known key found for this signature in database
GPG key ID: B6C15EBA0357C9AA
2 changed files with 31 additions and 9 deletions

View file

@ -43,6 +43,24 @@ about updates, check our
UPDATE_CHECK_COOLDOWN_SECS = 60 * 60 * 12 # Check for updates at most every 12 hours. UPDATE_CHECK_COOLDOWN_SECS = 60 * 60 * 12 # Check for updates at most every 12 hours.
class UpdateCheckPrompt(Alert):
"""The prompt that asks the users if they want to enable update checks."""
x_pressed = False
def closeEvent(self, event: QtCore.QEvent) -> None:
"""Detect when a user has pressed "X" in the title bar.
This function is called when a user clicks on "X" in the title bar. We want to
differentiate between the user clicking on "Cancel" and clicking on "X", since
in the second case, we want to remind them again on the next run.
See: https://stackoverflow.com/questions/70851063/pyqt-differentiate-between-close-function-and-title-bar-close-x
"""
self.x_pressed = True
event.accept()
class UpdateReport: class UpdateReport:
"""A report for an update check.""" """A report for an update check."""
@ -98,17 +116,20 @@ class UpdaterThread(QtCore.QThread):
def check(self, val: bool) -> None: def check(self, val: bool) -> None:
self.dangerzone.settings.set("updater_check", val, autosave=True) self.dangerzone.settings.set("updater_check", val, autosave=True)
def prompt_for_checks(self) -> bool: def prompt_for_checks(self) -> Optional[bool]:
"""Ask the user if they want to be informed about Dangerzone updates.""" """Ask the user if they want to be informed about Dangerzone updates."""
log.debug("Prompting the user for update checks") log.debug("Prompting the user for update checks")
# FIXME: Handle the case where a user clicks on "X", instead of explicitly # FIXME: Handle the case where a user clicks on "X", instead of explicitly
# making a choice. We should probably ask them again on the next run. # making a choice. We should probably ask them again on the next run.
check = Alert( prompt = UpdateCheckPrompt(
self.dangerzone, self.dangerzone,
message=MSG_CONFIRM_UPDATE_CHECKS, message=MSG_CONFIRM_UPDATE_CHECKS,
ok_text="Yes", ok_text="Yes",
cancel_text="No", cancel_text="No",
).launch() )
check = prompt.launch()
if not check and prompt.x_pressed:
return None
return bool(check) return bool(check)
def should_check_for_updates(self) -> bool: def should_check_for_updates(self) -> bool:
@ -140,7 +161,7 @@ class UpdaterThread(QtCore.QThread):
if self.check is None: if self.check is None:
log.debug("User has not been asked yet for update checks") log.debug("User has not been asked yet for update checks")
self.check = self.prompt_for_checks() self.check = self.prompt_for_checks()
return self.check return bool(self.check)
elif not self.check: elif not self.check:
log.debug("User has expressed that they don't want to check for updates") log.debug("User has expressed that they don't want to check for updates")
return False return False

View file

@ -156,18 +156,19 @@ def test_user_prompts(
# #
# When Dangerzone runs for a second time, users can be prompted to enable update # When Dangerzone runs for a second time, users can be prompted to enable update
# checks. Depending on their answer, we should either enable or disable them. # checks. Depending on their answer, we should either enable or disable them.
alert_mock = mocker.MagicMock() mocker.patch("dangerzone.gui.updater.UpdateCheckPrompt")
monkeypatch.setattr(updater_module, "Alert", alert_mock) prompt_mock = updater_module.UpdateCheckPrompt
prompt_mock().x_pressed = False
# Check disabling update checks. # Check disabling update checks.
alert_mock().launch.return_value = False prompt_mock().launch.return_value = False # type: ignore [attr-defined]
expected_settings["updater_check"] = False expected_settings["updater_check"] = False
assert updater.should_check_for_updates() == False assert updater.should_check_for_updates() == False
assert updater.dangerzone.settings.get_updater_settings() == expected_settings assert updater.dangerzone.settings.get_updater_settings() == expected_settings
# Reset the "updater_check" field and check enabling update checks. # Reset the "updater_check" field and check enabling update checks.
updater.dangerzone.settings.set("updater_check", None) updater.dangerzone.settings.set("updater_check", None)
alert_mock().launch.return_value = True prompt_mock().launch.return_value = True # type: ignore [attr-defined]
expected_settings["updater_check"] = True expected_settings["updater_check"] = True
assert updater.should_check_for_updates() == True assert updater.should_check_for_updates() == True
assert updater.dangerzone.settings.get_updater_settings() == expected_settings assert updater.dangerzone.settings.get_updater_settings() == expected_settings
@ -176,7 +177,7 @@ def test_user_prompts(
# #
# From the third run onwards, users should never be prompted for enabling update # From the third run onwards, users should never be prompted for enabling update
# checks. # checks.
alert_mock.side_effect = RuntimeError("Should not be called") prompt_mock().side_effect = RuntimeError("Should not be called") # type: ignore [attr-defined]
for check in [True, False]: for check in [True, False]:
updater.dangerzone.settings.set("updater_check", check) updater.dangerzone.settings.set("updater_check", check)
assert updater.should_check_for_updates() == check assert updater.should_check_for_updates() == check