From 936865b8b2ec28f520436a4d7aa5768eebbe9882 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Thu, 17 Apr 2025 12:28:26 -0500 Subject: [PATCH 01/12] [IMP] Disable screensaver during SeedQR transcription Disables the screensaver entirely while the SeedQR transcription routine is active. Any view can be configured to allow or disallow screensaver activation. --- src/seedsigner/controller.py | 7 ++++++- src/seedsigner/hardware/buttons.py | 8 +++++++- src/seedsigner/views/seed_views.py | 3 ++- src/seedsigner/views/view.py | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index d8a3467a..667d7753 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -1,6 +1,7 @@ import logging import time import traceback +from typing import Optional from embit.descriptor import Descriptor from embit.psbt import PSBT @@ -14,7 +15,7 @@ from seedsigner.models.settings import Settings 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 +467,7 @@ class Controller(Singleton): exception_msg, ] return Destination(UnhandledExceptionView, view_args={"error": error}, clear_history=True) + + @property + def active_view(self) -> Optional[View]: + return self.back_stack[-1].view if self.back_stack else None diff --git a/src/seedsigner/hardware/buttons.py b/src/seedsigner/hardware/buttons.py index 2f1a6725..450b009c 100644 --- a/src/seedsigner/hardware/buttons.py +++ b/src/seedsigner/hardware/buttons.py @@ -89,7 +89,13 @@ class HardwareButtons(Singleton): 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: + active_view = controller.active_view + active_view_allows_screensaver = True + if active_view: + active_view_allows_screensaver = active_view.allow_screensaver + + if (cur_time - self.last_input_time > controller.screensaver_activation_ms + and not controller.is_screensaver_running and active_view_allows_screensaver): # 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 cd7d9cc9..74438153 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -1567,7 +1567,8 @@ class SeedTranscribeSeedQRZoomedInView(View): 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.allow_screensaver = False def run(self): diff --git a/src/seedsigner/views/view.py b/src/seedsigner/views/view.py index 66c3a229..425ec222 100644 --- a/src/seedsigner/views/view.py +++ b/src/seedsigner/views/view.py @@ -67,6 +67,7 @@ class View: self.screen = None self._redirect: 'Destination' = None + self.allow_screensaver = True def __init__(self): From 1c0737b1950fdbb1984c45a21e59235035d1dc92 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Sun, 20 Apr 2025 02:43:13 -0500 Subject: [PATCH 02/12] [FIX] active_view returns MainMenuView when back stack is empty --- src/seedsigner/controller.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index 667d7753..c60fe143 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -1,7 +1,6 @@ import logging import time import traceback -from typing import Optional from embit.descriptor import Descriptor from embit.psbt import PSBT @@ -471,3 +470,7 @@ class Controller(Singleton): @property def active_view(self) -> Optional[View]: return self.back_stack[-1].view if self.back_stack else None + def active_view(self) -> View: + from seedsigner.views import MainMenuView + return self.back_stack[-1].view if self.back_stack else MainMenuView() + From b0276b73a25d2b53faec64dba9582521ae0d0ff6 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Sun, 20 Apr 2025 02:44:53 -0500 Subject: [PATCH 03/12] [IMP] can_run_screensaver implemented to handle screensaver runable logics --- src/seedsigner/controller.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index c60fe143..8e43ae10 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -468,9 +468,19 @@ class Controller(Singleton): return Destination(UnhandledExceptionView, view_args={"error": error}, clear_history=True) @property - def active_view(self) -> Optional[View]: - return self.back_stack[-1].view if self.back_stack else None def active_view(self) -> View: from seedsigner.views import MainMenuView return self.back_stack[-1].view if self.back_stack else MainMenuView() + def can_run_screensaver(self) -> bool: + """ + Determines whether the screensaver is allowed to run. + + The screensaver can run only if: + - It is not currently running. + - The current active view allows screensaver activity. + + Returns: + bool: True if the screensaver can run, False otherwise. + """ + return not self.is_screensaver_running and self.active_view.allow_screensaver From 499a17a6ec7b382276257d3b94bbcd0c844a2094 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Sun, 20 Apr 2025 02:46:36 -0500 Subject: [PATCH 04/12] [IMP] code cleanup --- src/seedsigner/hardware/buttons.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/seedsigner/hardware/buttons.py b/src/seedsigner/hardware/buttons.py index 450b009c..2e8c53b2 100644 --- a/src/seedsigner/hardware/buttons.py +++ b/src/seedsigner/hardware/buttons.py @@ -89,13 +89,7 @@ class HardwareButtons(Singleton): return HardwareButtonsConstants.OVERRIDE cur_time = int(time.time() * 1000) - active_view = controller.active_view - active_view_allows_screensaver = True - if active_view: - active_view_allows_screensaver = active_view.allow_screensaver - - if (cur_time - self.last_input_time > controller.screensaver_activation_ms - and not controller.is_screensaver_running and active_view_allows_screensaver): + if cur_time - self.last_input_time > controller.screensaver_activation_ms and controller.can_run_screensaver(): # Start the screensaver. Will block execution until input detected. controller.start_screensaver() From a0fdfb187c396945478541b72e222290658b06a3 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Mon, 21 Apr 2025 20:41:45 -0500 Subject: [PATCH 05/12] [REF] active_view property removed and can_start_screensaver renamed to is_screensaver_start_allowed --- src/seedsigner/controller.py | 10 ++++------ src/seedsigner/hardware/buttons.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index 8e43ae10..07265a32 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -468,11 +468,7 @@ class Controller(Singleton): return Destination(UnhandledExceptionView, view_args={"error": error}, clear_history=True) @property - def active_view(self) -> View: - from seedsigner.views import MainMenuView - return self.back_stack[-1].view if self.back_stack else MainMenuView() - - def can_run_screensaver(self) -> bool: + def is_screensaver_start_allowed(self) -> bool: """ Determines whether the screensaver is allowed to run. @@ -483,4 +479,6 @@ class Controller(Singleton): Returns: bool: True if the screensaver can run, False otherwise. """ - return not self.is_screensaver_running and self.active_view.allow_screensaver + from seedsigner.views import MainMenuView + active_view = self.back_stack[-1].view if self.back_stack else MainMenuView() + return not self.is_screensaver_running and active_view.allow_screensaver diff --git a/src/seedsigner/hardware/buttons.py b/src/seedsigner/hardware/buttons.py index 2e8c53b2..c98fdea1 100644 --- a/src/seedsigner/hardware/buttons.py +++ b/src/seedsigner/hardware/buttons.py @@ -89,7 +89,7 @@ class HardwareButtons(Singleton): return HardwareButtonsConstants.OVERRIDE cur_time = int(time.time() * 1000) - if cur_time - self.last_input_time > controller.screensaver_activation_ms and controller.can_run_screensaver(): + 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() From 0f183fdb3cc13f30c0eabec24bb4c7b48d6b37d8 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Sun, 27 Apr 2025 02:32:35 -0500 Subject: [PATCH 06/12] [Temporary] rough test included that test the screensaver start status when the current view is SeedTranscribeSeedQRZoomedInView --- tests/test_flows_seed.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index a9a7f663..3f85c888 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -476,6 +476,25 @@ class TestSeedFlows(FlowTest): 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): From c85de0947680e2f390fc888f0315e4d53de27493 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Sun, 27 Apr 2025 02:37:16 -0500 Subject: [PATCH 07/12] [Temporary] TODO added --- tests/test_flows_seed.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index 3f85c888..c62547ad 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -476,6 +476,7 @@ class TestSeedFlows(FlowTest): FlowStep(seed_views.SeedOptionsView), ]) + # TODO: ideally this test should be part of controller related test? move it there def test_transcribe_seedqr_screensaver_startable_status(self): """ The controller should return False for screensaver startable status when SeedTranscribeSeedQRZoomedInView From fee38bd94e82ef957b5947a030cb1e59ea10cf99 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Wed, 30 Jul 2025 04:31:01 -0500 Subject: [PATCH 08/12] Seedsigner 2 lines convention for method --- src/seedsigner/controller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index 07265a32..032e7ff2 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -467,6 +467,7 @@ class Controller(Singleton): ] return Destination(UnhandledExceptionView, view_args={"error": error}, clear_history=True) + @property def is_screensaver_start_allowed(self) -> bool: """ From dfa445b765c2d590780666557525a0ae82303031 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Wed, 30 Jul 2025 04:31:18 -0500 Subject: [PATCH 09/12] doc string update --- src/seedsigner/controller.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index 032e7ff2..bec52ede 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -471,14 +471,11 @@ class Controller(Singleton): @property def is_screensaver_start_allowed(self) -> bool: """ - Determines whether the screensaver is allowed to run. + Determines whether the screensaver is allowed to start. - The screensaver can run only if: - - It is not currently running. - - The current active view allows screensaver activity. - - Returns: - bool: True if the screensaver can run, False otherwise. + The screensaver can start only if: + - It is not currently running. + - The current active view allows screensaver activity. """ from seedsigner.views import MainMenuView active_view = self.back_stack[-1].view if self.back_stack else MainMenuView() From 8440d451479297a299ccce0fc5641b209e87ffab Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Wed, 30 Jul 2025 04:31:54 -0500 Subject: [PATCH 10/12] backstack comment update --- src/seedsigner/controller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index bec52ede..e3736a7a 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -478,5 +478,6 @@ class Controller(Singleton): - 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.allow_screensaver From d92f377dc945c333616f87cc3f36190b2faea81c Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Wed, 30 Jul 2025 04:33:01 -0500 Subject: [PATCH 11/12] property renamed as per suggestion --- src/seedsigner/controller.py | 2 +- src/seedsigner/views/seed_views.py | 2 +- src/seedsigner/views/view.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index e3736a7a..5ea62246 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -480,4 +480,4 @@ class Controller(Singleton): 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.allow_screensaver + return not self.is_screensaver_running and active_view.is_screensaver_allowed diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index 74438153..7c99a29a 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -1568,7 +1568,7 @@ class SeedTranscribeSeedQRZoomedInView(View): self.seed = self.controller.get_seed(seed_num) self.initial_zone_x = initial_zone_x self.initial_zone_y = initial_zone_y - self.allow_screensaver = False + self.is_screensaver_allowed = False def run(self): diff --git a/src/seedsigner/views/view.py b/src/seedsigner/views/view.py index 425ec222..7412932c 100644 --- a/src/seedsigner/views/view.py +++ b/src/seedsigner/views/view.py @@ -67,7 +67,7 @@ class View: self.screen = None self._redirect: 'Destination' = None - self.allow_screensaver = True + self.is_screensaver_allowed = True def __init__(self): From 8e9fa85dae9846122cf6c8418b467dff792d2ae5 Mon Sep 17 00:00:00 2001 From: FazleRabbbiferdaus172 Date: Wed, 30 Jul 2025 04:33:27 -0500 Subject: [PATCH 12/12] todo removed --- tests/test_flows_seed.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index c62547ad..3f85c888 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -476,7 +476,6 @@ class TestSeedFlows(FlowTest): FlowStep(seed_views.SeedOptionsView), ]) - # TODO: ideally this test should be part of controller related test? move it there def test_transcribe_seedqr_screensaver_startable_status(self): """ The controller should return False for screensaver startable status when SeedTranscribeSeedQRZoomedInView