diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index d8a3467a9..5ea622469 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -14,7 +14,7 @@ from seedsigner.models.singleton import Singleton from seedsigner.models.threads import BaseThread from seedsigner.views.screensaver import ScreensaverScreen -from seedsigner.views.view import Destination +from seedsigner.views.view import Destination, View logger = logging.getLogger(__name__) @@ -466,3 +466,18 @@ def handle_exception(self, e) -> Destination: exception_msg, ] return Destination(UnhandledExceptionView, view_args={"error": error}, clear_history=True) + + + @property + def is_screensaver_start_allowed(self) -> bool: + """ + Determines whether the screensaver is allowed to start. + + The screensaver can start only if: + - It is not currently running. + - The current active view allows screensaver activity. + """ + from seedsigner.views import MainMenuView + # Confusingly, the top item in the `BackStack` is actually the *current* View + active_view = self.back_stack[-1].view if self.back_stack else MainMenuView() + return not self.is_screensaver_running and active_view.is_screensaver_allowed diff --git a/src/seedsigner/hardware/buttons.py b/src/seedsigner/hardware/buttons.py index 2f1a6725f..c98fdea13 100644 --- a/src/seedsigner/hardware/buttons.py +++ b/src/seedsigner/hardware/buttons.py @@ -89,7 +89,7 @@ def wait_for(self, keys=[]) -> int: return HardwareButtonsConstants.OVERRIDE cur_time = int(time.time() * 1000) - if cur_time - self.last_input_time > controller.screensaver_activation_ms and not controller.is_screensaver_running: + if cur_time - self.last_input_time > controller.screensaver_activation_ms and controller.is_screensaver_start_allowed: # Start the screensaver. Will block execution until input detected. controller.start_screensaver() diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index cd7d9cc9e..7c99a29a3 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -1567,7 +1567,8 @@ def __init__(self, seed_num: int, seedqr_format: str, initial_zone_x: int = 0, i self.seedqr_format = seedqr_format self.seed = self.controller.get_seed(seed_num) self.initial_zone_x = initial_zone_x - self.initial_zone_y = initial_zone_y + self.initial_zone_y = initial_zone_y + self.is_screensaver_allowed = False def run(self): diff --git a/src/seedsigner/views/view.py b/src/seedsigner/views/view.py index 66c3a2293..7412932cd 100644 --- a/src/seedsigner/views/view.py +++ b/src/seedsigner/views/view.py @@ -67,6 +67,7 @@ def _initialize(self): self.screen = None self._redirect: 'Destination' = None + self.is_screensaver_allowed = True def __init__(self): diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index a9a7f6631..3f85c888d 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -476,6 +476,25 @@ def load_right_seed_into_decoder(view: View): FlowStep(seed_views.SeedOptionsView), ]) + def test_transcribe_seedqr_screensaver_startable_status(self): + """ + The controller should return False for screensaver startable status when SeedTranscribeSeedQRZoomedInView + is active. + """ + # Load a finalized Seed into the Controller + mnemonic = ["abandon"] * 11 + ["about"] + self.controller.storage.set_pending_seed(Seed(mnemonic=mnemonic)) + self.controller.storage.finalize_pending_seed() + + self.run_sequence( + initial_destination_view_args={'num_modules': 21, 'seed_num': 0, 'seedqr_format': 'seed__seedqr'}, + sequence=[ + FlowStep(seed_views.SeedTranscribeSeedQRWholeQRView), + FlowStep(seed_views.SeedTranscribeSeedQRZoomedInView, is_redirect=True), # Live interactive screens are a bit weird; not sure why `is_redirect` is necessary here + ]) + + assert self.controller.is_screensaver_start_allowed == False + class TestMessageSigningFlows(FlowTest):