mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 15:08:25 +00:00
Option MICROSD_TOAST_TIMER_FOREVER refactor
- Prevent escaping the RemoveMicroSDWarningView by launching SettingsEntryUpdateSelectionView in a blocking mode. If the tracked setting remains unchanged, Back/normal navigation returns to the blocking view (RemoveMicroSDWarningView). - Only 2 ways of escaping this mode: 1) physically removing MicroSD and 2) modifying the setting - Add test tests/test_flows.py::TestFlowTest::test_remove_microsd_blocking covering:
This commit is contained in:
@@ -150,11 +150,15 @@ class SettingsEntryUpdateSelectionView(View):
|
||||
Handles changes to all selection-type settings (Multiselect, SELECT_1,
|
||||
Enabled/Disabled, etc).
|
||||
"""
|
||||
def __init__(self, attr_name: str, parent_initial_scroll: int = 0, selected_button: int = None):
|
||||
def __init__(self, attr_name: str, parent_initial_scroll: int = 0, selected_button: int = None, blocking_view: View = None, unblocking_view: View = None):
|
||||
super().__init__()
|
||||
self.settings_entry = SettingsDefinition.get_settings_entry(attr_name)
|
||||
self.selected_button = selected_button
|
||||
self.parent_initial_scroll = parent_initial_scroll
|
||||
# If the setting remains unchanged, navigation should return to blocking_view (if set)
|
||||
self.blocking_view = blocking_view
|
||||
# unblocking_view is an optional target to navigate to once the setting actually changes.
|
||||
self.unblocking_view = unblocking_view
|
||||
|
||||
|
||||
def run(self):
|
||||
@@ -200,6 +204,8 @@ class SettingsEntryUpdateSelectionView(View):
|
||||
)
|
||||
|
||||
if ret_value == RET_CODE__BACK_BUTTON:
|
||||
if self.blocking_view:
|
||||
return Destination(self.blocking_view, clear_history=True)
|
||||
return settings_menu_view_destination
|
||||
|
||||
value = self.settings_entry.get_selection_option_value(ret_value)
|
||||
@@ -219,8 +225,7 @@ class SettingsEntryUpdateSelectionView(View):
|
||||
|
||||
else:
|
||||
# All other types are single selects (e.g. Enabled/Disabled, SELECT_1)
|
||||
if value == initial_value:
|
||||
# No change, return to menu
|
||||
if value == initial_value and not self.blocking_view:
|
||||
return settings_menu_view_destination
|
||||
else:
|
||||
updated_value = value
|
||||
@@ -238,11 +243,21 @@ class SettingsEntryUpdateSelectionView(View):
|
||||
|
||||
if destination:
|
||||
return destination
|
||||
|
||||
# If this selection view was opened from a blocking flow (e.g. RemoveMicroSDWarningView),
|
||||
# prevent navigation away until the setting actually changes. If it hasn't changed,
|
||||
# return to the blocking view so it can re-evaluate the state.
|
||||
if self.blocking_view:
|
||||
current_value = self.settings.get_value(self.settings_entry.attr_name)
|
||||
if current_value == initial_value:
|
||||
return Destination(self.blocking_view, clear_history=True)
|
||||
elif self.unblocking_view:
|
||||
return Destination(self.unblocking_view, clear_history=True)
|
||||
|
||||
# All selects stay in place; re-initialize where in the list we left off
|
||||
self.selected_button = ret_value
|
||||
|
||||
return Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=self.settings_entry.attr_name, parent_initial_scroll=self.parent_initial_scroll, selected_button=self.selected_button), skip_current_view=True)
|
||||
return Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=self.settings_entry.attr_name, parent_initial_scroll=self.parent_initial_scroll, selected_button=self.selected_button, blocking_view=self.blocking_view, unblocking_view=self.unblocking_view), skip_current_view=True)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -412,10 +412,10 @@ class OptionDisabledView(View):
|
||||
|
||||
class RemoveMicroSDWarningView(View):
|
||||
CONTINUE = ButtonOption("Continue")
|
||||
DISMISS = ButtonOption("Dismiss")
|
||||
SETTINGS = ButtonOption("Settings")
|
||||
|
||||
def run(self):
|
||||
button_data = [self.CONTINUE, self.DISMISS]
|
||||
button_data = [self.CONTINUE, self.SETTINGS]
|
||||
selected_menu_num = self.run_screen(
|
||||
WarningScreen,
|
||||
title=_("Action Required"),
|
||||
@@ -426,8 +426,20 @@ class RemoveMicroSDWarningView(View):
|
||||
button_data=button_data,
|
||||
)
|
||||
|
||||
from seedsigner.hardware.microsd import MicroSD
|
||||
if button_data[selected_menu_num] == self.CONTINUE and MicroSD.get_instance().is_inserted:
|
||||
return Destination(RemoveMicroSDWarningView, clear_history=True)
|
||||
else:
|
||||
return Destination(MainMenuView, clear_history=True)
|
||||
if button_data[selected_menu_num] == self.CONTINUE:
|
||||
from seedsigner.hardware.microsd import MicroSD
|
||||
if not MicroSD.get_instance().is_inserted:
|
||||
return Destination(MainMenuView, clear_history=True)
|
||||
else:
|
||||
return Destination(RemoveMicroSDWarningView, clear_history=True)
|
||||
|
||||
elif button_data[selected_menu_num] == self.SETTINGS:
|
||||
from seedsigner.views.settings_views import SettingsEntryUpdateSelectionView
|
||||
return Destination(
|
||||
SettingsEntryUpdateSelectionView,
|
||||
view_args=dict(
|
||||
attr_name=SettingsConstants.SETTING__MICROSD_TOAST_TIMER,
|
||||
blocking_view=RemoveMicroSDWarningView,
|
||||
unblocking_view=MainMenuView
|
||||
)
|
||||
)
|
||||
+49
-1
@@ -9,8 +9,12 @@ from seedsigner.models.seed import Seed
|
||||
from seedsigner.views import scan_views
|
||||
from seedsigner.views.psbt_views import PSBTSelectSeedView
|
||||
from seedsigner.views.seed_views import SeedBackupView, SeedMnemonicEntryView, SeedOptionsView, SeedsMenuView
|
||||
from seedsigner.views.view import Destination, MainMenuView, PowerOptionsView, UnhandledExceptionView, View
|
||||
from seedsigner.views.view import Destination, MainMenuView, PowerOptionsView, UnhandledExceptionView, RemoveMicroSDWarningView, MainMenuView, View
|
||||
from seedsigner.views.tools_views import ToolsMenuView, ToolsCalcFinalWordNumWordsView
|
||||
from seedsigner.views.settings_views import SettingsEntryUpdateSelectionView
|
||||
from seedsigner.models.settings_definition import SettingsDefinition
|
||||
from seedsigner.models.settings import SettingsConstants
|
||||
from seedsigner.hardware.microsd import MicroSD
|
||||
|
||||
|
||||
|
||||
@@ -192,3 +196,47 @@ class TestFlowTest(FlowTest):
|
||||
FlowStep(MainMenuView), # Need a next Destination to force the first step to run
|
||||
])
|
||||
|
||||
def test_remove_microsd_blocking(self):
|
||||
"""
|
||||
Verifies three related behaviors:
|
||||
|
||||
1) If the RemoveMicroSDWarningView launches the SettingsEntryUpdateSelectionView
|
||||
and the user presses Back without changing the tracked setting, the flow
|
||||
returns to RemoveMicroSDWarningView (the blocking condition remains).
|
||||
2) If the user changes the tracked setting while in the settings entry, the
|
||||
flow unblocks and navigates to MainMenuView.
|
||||
3) If the MicroSD is physically removed and the user presses Continue on the
|
||||
warning, the flow proceeds to MainMenuView.
|
||||
"""
|
||||
controller = Controller.get_instance()
|
||||
|
||||
settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__MICROSD_TOAST_TIMER)
|
||||
controller.settings.set_value(settings_entry.attr_name, SettingsConstants.MICROSD_TOAST_TIMER_FOREVER)
|
||||
|
||||
# There are only two ways of exiting RemoveMicroSDWarningView when SETTING__MICROSD_TOAST_TIMER -> MICROSD_TOAST_TIMER_FOREVER
|
||||
self.run_sequence([
|
||||
FlowStep(RemoveMicroSDWarningView, button_data_selection=RemoveMicroSDWarningView.SETTINGS),
|
||||
FlowStep(SettingsEntryUpdateSelectionView, screen_return_value=RET_CODE__BACK_BUTTON),
|
||||
FlowStep(RemoveMicroSDWarningView, button_data_selection=RemoveMicroSDWarningView.SETTINGS),
|
||||
# 1) Modifying the setting
|
||||
FlowStep(SettingsEntryUpdateSelectionView, screen_return_value=0),
|
||||
FlowStep(MainMenuView)
|
||||
])
|
||||
|
||||
self.reset_controller()
|
||||
controller = Controller.get_instance()
|
||||
|
||||
settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__MICROSD_TOAST_TIMER)
|
||||
controller.settings.set_value(settings_entry.attr_name, SettingsConstants.MICROSD_TOAST_TIMER_FOREVER)
|
||||
|
||||
# 2) Removing the MicroSD card and pressing CONTINUE
|
||||
self.mock_microsd.is_inserted = False
|
||||
assert MicroSD.get_instance().is_inserted is False
|
||||
|
||||
self.run_sequence([
|
||||
FlowStep(RemoveMicroSDWarningView, button_data_selection=RemoveMicroSDWarningView.CONTINUE),
|
||||
FlowStep(MainMenuView)
|
||||
])
|
||||
|
||||
# Restore the setting for the controller
|
||||
controller.settings.set_value(settings_entry.attr_name, SettingsConstants.MICROSD_TOAST_TIMER_FIVE_SECONDS)
|
||||
Reference in New Issue
Block a user