mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-06 07:28:24 +00:00
cleanup, light refactor, new test
This commit is contained in:
@@ -313,7 +313,6 @@ class TextArea(BaseComponent):
|
||||
)
|
||||
|
||||
# Calculate the actual font height from the "baseline" anchor ("_s")
|
||||
height_calc_start = time()
|
||||
font = Fonts.get_font(self.font_name, self.font_size)
|
||||
|
||||
# Note: from the baseline anchor, `top` is a negative number while `bottom`
|
||||
@@ -325,8 +324,6 @@ class TextArea(BaseComponent):
|
||||
# Initialize the text rendering relative to the baseline
|
||||
self.text_y = self.text_height_above_baseline
|
||||
|
||||
print(f"{time() - height_calc_start}s to calc self.text_font_height")
|
||||
|
||||
# Other components, like IconTextLine will need to know how wide the actual
|
||||
# rendered text will be, separate from the TextArea's defined overall `width`.
|
||||
self.text_width = max(line["text_width"] for line in self.text_lines)
|
||||
@@ -1485,15 +1482,31 @@ def reflow_text_for_width(text: str,
|
||||
|
||||
|
||||
|
||||
def break_lines_into_pages(lines: list[str],
|
||||
def reflow_text_into_pages(text: str,
|
||||
width: int,
|
||||
height: int,
|
||||
font_name=GUIConstants.BODY_FONT_NAME,
|
||||
font_size=GUIConstants.BODY_FONT_SIZE,
|
||||
line_spacer: int = GUIConstants.BODY_LINE_SPACING) -> list[str]:
|
||||
line_spacer: int = GUIConstants.BODY_LINE_SPACING,
|
||||
allow_text_overflow: bool=False) -> list[str]:
|
||||
"""
|
||||
After splitting a long text into width-limited individual text lines, now calculate
|
||||
how many lines will fit on a "page" and group accordingly.
|
||||
Invokes `reflow_text_for_width` above to convert long text into width-limited
|
||||
individual text lines and then calculates how many lines will fit on a "page" and
|
||||
groups the output accordingly.
|
||||
|
||||
Returns a list of strings where each string is a page's worth of line-breaked text.
|
||||
"""
|
||||
reflowed_lines_dicts = reflow_text_for_width(text=text,
|
||||
width=width,
|
||||
font_name=font_name,
|
||||
font_size=font_size,
|
||||
allow_text_overflow=allow_text_overflow)
|
||||
|
||||
lines = []
|
||||
for line_dict in reflowed_lines_dicts:
|
||||
lines.append(line_dict["text"])
|
||||
print(f"""{line_dict["text_width"]:3}: {line_dict["text"]}""")
|
||||
|
||||
font = Fonts.get_font(font_name=font_name, size=font_size)
|
||||
# Measure the font's height above baseline via the "baseline" anchor ("_s")
|
||||
(left, top, right, bottom) = font.getbbox("Agjpqy", anchor="ls")
|
||||
@@ -1503,7 +1516,7 @@ def break_lines_into_pages(lines: list[str],
|
||||
# I'm sure there's a smarter way to do this...
|
||||
lines_per_page = 0
|
||||
for i in range(1, height):
|
||||
if height > font_height_above_baseline * i + line_spacer * (i-1) + bottom:
|
||||
if height > font_height_above_baseline * i + line_spacer * (i-1) + font_height_below_baseline:
|
||||
lines_per_page = i
|
||||
else:
|
||||
break
|
||||
|
||||
@@ -11,7 +11,7 @@ from seedsigner.models.threads import BaseThread, ThreadsafeCounter
|
||||
|
||||
from .screen import RET_CODE__BACK_BUTTON, BaseScreen, BaseTopNavScreen, ButtonListScreen, KeyboardScreen, WarningEdgesMixin
|
||||
from ..components import (Button, FontAwesomeIconConstants, Fonts, FormattedAddress, IconButton,
|
||||
IconTextLine, SeedSignerIconConstants, TextArea, GUIConstants, reflow_text_for_width, break_lines_into_pages)
|
||||
IconTextLine, SeedSignerIconConstants, TextArea, GUIConstants, reflow_text_into_pages)
|
||||
|
||||
from seedsigner.gui.keyboard import Keyboard, TextEntryDisplay
|
||||
from seedsigner.hardware.buttons import HardwareButtons, HardwareButtonsConstants
|
||||
@@ -1512,22 +1512,10 @@ class SeedSignMessageConfirmMessageScreen(ButtonListScreen):
|
||||
|
||||
self.sign_message_data = Controller.get_instance().sign_message_data
|
||||
if "paged_message" not in self.sign_message_data:
|
||||
reflowed_lines_dicts = reflow_text_for_width(
|
||||
paged = reflow_text_into_pages(
|
||||
text=self.sign_message_data["message"],
|
||||
width=renderer.canvas_width - 2*GUIConstants.EDGE_PADDING,
|
||||
font_name=GUIConstants.BODY_FONT_NAME,
|
||||
font_size=GUIConstants.BODY_FONT_SIZE,
|
||||
allow_text_overflow=True,
|
||||
)
|
||||
|
||||
lines = []
|
||||
for line_dict in reflowed_lines_dicts:
|
||||
lines.append(line_dict["text"])
|
||||
print(f"""{line_dict["text_width"]:3}: {line_dict["text"]}""")
|
||||
|
||||
paged = break_lines_into_pages(
|
||||
lines=lines,
|
||||
height=message_height
|
||||
height=message_height,
|
||||
)
|
||||
self.sign_message_data["paged_message"] = paged
|
||||
|
||||
|
||||
@@ -113,6 +113,13 @@ def get_embit_network_name(settings_name):
|
||||
|
||||
|
||||
def parse_derivation_path(derivation_path: str) -> dict:
|
||||
"""
|
||||
Parses a derivation path into its related SettingsConstants equivalents.
|
||||
|
||||
Primarily only supports single sig derivation paths.
|
||||
|
||||
May return None for fields it cannot parse.
|
||||
"""
|
||||
# Support either m/44'/... or m/44h/... style
|
||||
derivation_path = derivation_path.replace("'", "h")
|
||||
|
||||
@@ -136,14 +143,18 @@ def parse_derivation_path(derivation_path: str) -> dict:
|
||||
|
||||
details = dict()
|
||||
details["script_type"] = lookups["script_types"].get(sections[1])
|
||||
if not details["script_type"]:
|
||||
details["script_type"] = SettingsConstants.CUSTOM_DERIVATION
|
||||
details["network"] = lookups["networks"].get(sections[2])
|
||||
details["is_change"] = sections[-2] == "1"
|
||||
details["index"] = int(sections[-1])
|
||||
|
||||
if details["script_type"] and details["network"] and sections[3] == "0h":
|
||||
details["clean_match"] = True
|
||||
else:
|
||||
details["clean_match"] = False
|
||||
details["clean_match"] = True
|
||||
for k, v in details.items():
|
||||
if v is None:
|
||||
# At least one field couldn't be parsed
|
||||
details["clean_match"] = False
|
||||
break
|
||||
|
||||
return details
|
||||
|
||||
|
||||
@@ -76,6 +76,12 @@ class SeedSelectSeedView(View):
|
||||
* `flow`: indicates which user flow is in progress during seed selection (e.g.
|
||||
verify single sig addr or sign message).
|
||||
"""
|
||||
SCAN_SEED = ("Scan a seed", FontAwesomeIconConstants.QRCODE)
|
||||
TYPE_12WORD = ("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
TYPE_24WORD = ("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
button_data = []
|
||||
|
||||
|
||||
def __init__(self, flow: str = Controller.FLOW__VERIFY_SINGLESIG_ADDR):
|
||||
super().__init__()
|
||||
self.flow = flow
|
||||
@@ -84,11 +90,6 @@ class SeedSelectSeedView(View):
|
||||
def run(self):
|
||||
seeds = self.controller.storage.seeds
|
||||
|
||||
SCAN_SEED = ("Scan a seed", FontAwesomeIconConstants.QRCODE)
|
||||
TYPE_12WORD = ("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
TYPE_24WORD = ("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
button_data = []
|
||||
|
||||
if self.flow == Controller.FLOW__VERIFY_SINGLESIG_ADDR:
|
||||
title = "Verify Address"
|
||||
if not seeds:
|
||||
@@ -106,24 +107,26 @@ class SeedSelectSeedView(View):
|
||||
else:
|
||||
raise Exception(f"Unsupported `flow` specified: {self.flow}")
|
||||
|
||||
self.button_data = []
|
||||
for seed in seeds:
|
||||
button_str = seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK))
|
||||
|
||||
if seed.passphrase is not None:
|
||||
# TODO: Include lock icon on right side of button
|
||||
pass
|
||||
button_data.append((button_str, SeedSignerCustomIconConstants.FINGERPRINT, "blue"))
|
||||
self.button_data.append((button_str, SeedSignerCustomIconConstants.FINGERPRINT, "blue"))
|
||||
|
||||
self.button_data.append(self.SCAN_SEED)
|
||||
self.button_data.append(self.TYPE_12WORD)
|
||||
self.button_data.append(self.TYPE_24WORD)
|
||||
|
||||
button_data.append(SCAN_SEED)
|
||||
button_data.append(TYPE_12WORD)
|
||||
button_data.append(TYPE_24WORD)
|
||||
|
||||
selected_menu_num = seed_screens.SeedSelectSeedScreen(
|
||||
selected_menu_num = self.run_screen(
|
||||
seed_screens.SeedSelectSeedScreen,
|
||||
title=title,
|
||||
text=text,
|
||||
is_button_text_centered=False,
|
||||
button_data=button_data
|
||||
).display()
|
||||
button_data=self.button_data
|
||||
)
|
||||
|
||||
if selected_menu_num == RET_CODE__BACK_BUTTON:
|
||||
return Destination(BackStackView)
|
||||
@@ -140,13 +143,13 @@ class SeedSelectSeedView(View):
|
||||
|
||||
self.controller.resume_main_flow = self.flow
|
||||
|
||||
if button_data[selected_menu_num] == SCAN_SEED:
|
||||
if self.button_data[selected_menu_num] == self.SCAN_SEED:
|
||||
from seedsigner.views.scan_views import ScanView
|
||||
return Destination(ScanView)
|
||||
|
||||
elif button_data[selected_menu_num] in [TYPE_12WORD, TYPE_24WORD]:
|
||||
elif self.button_data[selected_menu_num] in [self.TYPE_12WORD, self.TYPE_24WORD]:
|
||||
from seedsigner.views.seed_views import SeedMnemonicEntryView
|
||||
if button_data[selected_menu_num] == TYPE_12WORD:
|
||||
if self.button_data[selected_menu_num] == self.TYPE_12WORD:
|
||||
self.controller.storage.init_pending_mnemonic(num_words=12)
|
||||
else:
|
||||
self.controller.storage.init_pending_mnemonic(num_words=24)
|
||||
@@ -1995,7 +1998,7 @@ class SeedSignMessageStartView(View):
|
||||
class SeedSignMessageConfirmMessageView(View):
|
||||
def __init__(self, page_num: int = 0):
|
||||
super().__init__()
|
||||
self.page_num = page_num
|
||||
self.page_num = page_num # Note: zero-indexed numbering!
|
||||
|
||||
self.data = self.controller.sign_message_data
|
||||
self.seed_num = self.data.get("seed_num")
|
||||
@@ -2012,7 +2015,7 @@ class SeedSignMessageConfirmMessageView(View):
|
||||
)
|
||||
|
||||
if selected_menu_num == RET_CODE__BACK_BUTTON:
|
||||
if self.page_num == 1:
|
||||
if self.page_num == 0:
|
||||
# We're exiting this flow entirely
|
||||
self.controller.resume_main_flow = None
|
||||
self.controller.sign_message_data = None
|
||||
@@ -2021,7 +2024,7 @@ class SeedSignMessageConfirmMessageView(View):
|
||||
# User clicked "Next"
|
||||
if self.page_num == len(self.controller.sign_message_data["paged_message"]) - 1:
|
||||
# We've reached the end of the paged message
|
||||
return Destination(SeedSignMessageConfirmAddressView, skip_current_view=True)
|
||||
return Destination(SeedSignMessageConfirmAddressView)
|
||||
else:
|
||||
return Destination(SeedSignMessageConfirmMessageView, view_args=dict(page_num=self.page_num + 1))
|
||||
|
||||
|
||||
@@ -325,3 +325,68 @@ def test_get_multisig_address():
|
||||
print(f' {func.__name__}(descriptor=Descriptor.from_string("{descriptor}"), index={args[1]}, is_change={args[2]}, embit_network="{args[3]}") raises Exception"')
|
||||
func(descriptor=descriptor, index=args[1], is_change=args[2], embit_network=args[3])
|
||||
|
||||
|
||||
def test_parse_derivation_path():
|
||||
# Shouldn't care if input uses "'" or "h"
|
||||
derivation_path = "m/84'/0'/0'/0/0"
|
||||
|
||||
result = embit_utils.parse_derivation_path(derivation_path)
|
||||
assert(result["script_type"] == SC.NATIVE_SEGWIT)
|
||||
assert(result["network"] == SC.MAINNET)
|
||||
|
||||
result = embit_utils.parse_derivation_path(derivation_path.replace("'", "h"))
|
||||
assert(result["script_type"] == SC.NATIVE_SEGWIT)
|
||||
assert(result["network"] == SC.MAINNET)
|
||||
|
||||
# Now exhaustively test supported permutations
|
||||
vectors_args = {
|
||||
(SC.MAINNET, SC.NATIVE_SEGWIT, False): "m/84'/0'/0'/0/5",
|
||||
(SC.TESTNET, SC.NATIVE_SEGWIT, False): "m/84'/1'/0'/0/5",
|
||||
(SC.REGTEST, SC.NATIVE_SEGWIT, False): "m/84'/1'/0'/0/5",
|
||||
(SC.MAINNET, SC.NATIVE_SEGWIT, True): "m/84'/0'/0'/1/5",
|
||||
(SC.TESTNET, SC.NATIVE_SEGWIT, True): "m/84'/1'/0'/1/5",
|
||||
(SC.REGTEST, SC.NATIVE_SEGWIT, True): "m/84'/1'/0'/1/5",
|
||||
|
||||
(SC.MAINNET, SC.NESTED_SEGWIT, False): "m/49'/0'/0'/0/5",
|
||||
(SC.TESTNET, SC.NESTED_SEGWIT, False): "m/49'/1'/0'/0/5",
|
||||
(SC.REGTEST, SC.NESTED_SEGWIT, False): "m/49'/1'/0'/0/5",
|
||||
(SC.MAINNET, SC.NESTED_SEGWIT, True): "m/49'/0'/0'/1/5",
|
||||
(SC.TESTNET, SC.NESTED_SEGWIT, True): "m/49'/1'/0'/1/5",
|
||||
(SC.REGTEST, SC.NESTED_SEGWIT, True): "m/49'/1'/0'/1/5",
|
||||
|
||||
(SC.MAINNET, SC.TAPROOT, False): "m/86'/0'/0'/0/5",
|
||||
(SC.TESTNET, SC.TAPROOT, False): "m/86'/1'/0'/0/5",
|
||||
(SC.REGTEST, SC.TAPROOT, False): "m/86'/1'/0'/0/5",
|
||||
(SC.MAINNET, SC.TAPROOT, True): "m/86'/0'/0'/1/5",
|
||||
(SC.TESTNET, SC.TAPROOT, True): "m/86'/1'/0'/1/5",
|
||||
(SC.REGTEST, SC.TAPROOT, True): "m/86'/1'/0'/1/5",
|
||||
|
||||
# Try a typical custom derivation path (Unchained Capital)
|
||||
(SC.MAINNET, SC.CUSTOM_DERIVATION, False): "m/45'/0'/0'/0/5",
|
||||
(SC.TESTNET, SC.CUSTOM_DERIVATION, False): "m/45'/1'/0'/0/5",
|
||||
(SC.REGTEST, SC.CUSTOM_DERIVATION, False): "m/45'/1'/0'/0/5",
|
||||
(SC.MAINNET, SC.CUSTOM_DERIVATION, True): "m/45'/0'/0'/1/5",
|
||||
(SC.TESTNET, SC.CUSTOM_DERIVATION, True): "m/45'/1'/0'/1/5",
|
||||
(SC.REGTEST, SC.CUSTOM_DERIVATION, True): "m/45'/1'/0'/1/5",
|
||||
|
||||
# CRAZY custom derivation path
|
||||
(None, SC.CUSTOM_DERIVATION, False): "m/879345978543'/908327034508534983495'/9085098430894380959043'/0/5",
|
||||
}
|
||||
|
||||
for expected_result, derivation_path in vectors_args.items():
|
||||
actual_result = embit_utils.parse_derivation_path(derivation_path)
|
||||
|
||||
if expected_result[0] == SC.MAINNET:
|
||||
assert(actual_result["network"] == expected_result[0])
|
||||
assert(actual_result["clean_match"] is True)
|
||||
elif expected_result[0] is None:
|
||||
assert(actual_result["network"] is None)
|
||||
assert(actual_result["clean_match"] is False)
|
||||
else:
|
||||
# Testnet and regtest are returned as a list since the parser can't tell which is intended
|
||||
assert(expected_result[0] in actual_result["network"])
|
||||
assert(actual_result["clean_match"] is True)
|
||||
|
||||
assert(actual_result["script_type"] == expected_result[1])
|
||||
assert(actual_result["is_change"] == expected_result[2])
|
||||
assert(actual_result["index"] == int(derivation_path.split("/")[-1]))
|
||||
|
||||
+103
-1
@@ -3,9 +3,10 @@ from base import BaseTest, FlowTest, FlowStep
|
||||
from base import FlowTestRunScreenNotExecutedException, FlowTestInvalidButtonDataSelectionException
|
||||
|
||||
import pytest
|
||||
from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON
|
||||
from seedsigner.models.settings import SettingsConstants
|
||||
from seedsigner.models.seed import Seed
|
||||
from seedsigner.views.view import MainMenuView
|
||||
from seedsigner.views.view import MainMenuView, View
|
||||
from seedsigner.views import seed_views, scan_views
|
||||
|
||||
|
||||
@@ -288,3 +289,104 @@ class TestSeedFlows(FlowTest):
|
||||
FlowStep(seed_views.LoadSeedView),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
||||
def test_sign_message_flow(self):
|
||||
"""
|
||||
"""
|
||||
# Ensure message signing is enabled
|
||||
self.settings.set_value(SettingsConstants.SETTING__MESSAGE_SIGNING, SettingsConstants.OPTION__ENABLED)
|
||||
|
||||
def load_seed_into_decoder(view: scan_views.ScanView):
|
||||
view.decoder.add_data("0000" * 11 + "0003")
|
||||
|
||||
derivation_path = "m/84h/0h/0h/0/0"
|
||||
message = "I attest that I control this bitcoin address blah blah blah"
|
||||
multipage_message = """Chancellor on brink of second bailout for banks
|
||||
|
||||
Billions may be needed as lending squeeze tightens
|
||||
|
||||
Alistair Darling has been forced to consider a second bailout for banks as the lending drought worsens.
|
||||
|
||||
The Chancellor will decide within weeks whether to pump billions more into the economy as evidence mounts that the £37 billion part-nationalisation last year has failed to keep credit flowing. Options include cash injections, offering banks cheaper state guarantees to raise money privately or buying up “toxic assets”, The Times has learnt."""
|
||||
|
||||
|
||||
def load_standard_message_into_decoder(view: View):
|
||||
view.decoder.add_data(f"signmessage {derivation_path} ascii:{message}")
|
||||
|
||||
def load_multipage_message_into_decoder(view: View):
|
||||
view.decoder.add_data(f"signmessage {derivation_path} ascii:{multipage_message}")
|
||||
|
||||
def inject_mesage_as_paged_message(view: View):
|
||||
# Because the Screen won't actually run, we have to do the Screen's work here
|
||||
from seedsigner.gui.components import reflow_text_into_pages, GUIConstants
|
||||
paged = reflow_text_into_pages(
|
||||
text=self.controller.sign_message_data["message"],
|
||||
width=240 - 2*GUIConstants.EDGE_PADDING,
|
||||
height=240 - GUIConstants.TOP_NAV_HEIGHT - 3*GUIConstants.EDGE_PADDING - GUIConstants.BUTTON_HEIGHT,
|
||||
)
|
||||
self.controller.sign_message_data["paged_message"] = paged
|
||||
|
||||
# Scenario 1: Load the mesage first, then the seed
|
||||
self.run_sequence([
|
||||
FlowStep(MainMenuView, button_data_selection=MainMenuView.SCAN),
|
||||
FlowStep(scan_views.ScanView, before_run=load_standard_message_into_decoder), # simulate read message QR; ret val is ignored
|
||||
FlowStep(seed_views.SeedSignMessageStartView, is_redirect=True),
|
||||
FlowStep(seed_views.SeedSelectSeedView, button_data_selection=seed_views.SeedSelectSeedView.SCAN_SEED),
|
||||
FlowStep(scan_views.ScanView, before_run=load_seed_into_decoder), # simulate read SeedQR; ret val is ignored
|
||||
FlowStep(seed_views.SeedFinalizeView, button_data_selection=seed_views.SeedFinalizeView.FINALIZE),
|
||||
FlowStep(seed_views.SeedOptionsView, is_redirect=True),
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, before_run=inject_mesage_as_paged_message, screen_return_value=0),
|
||||
FlowStep(seed_views.SeedSignMessageConfirmAddressView, screen_return_value=0),
|
||||
FlowStep(seed_views.SeedSignMessageSignedMessageQRView, screen_return_value=0),
|
||||
FlowStep(MainMenuView),
|
||||
])
|
||||
|
||||
# Scenario 2: Scan the seed first, then select Sign Message
|
||||
self.controller.discard_seed(0)
|
||||
self.run_sequence([
|
||||
FlowStep(MainMenuView, button_data_selection=MainMenuView.SCAN),
|
||||
FlowStep(scan_views.ScanView, before_run=load_seed_into_decoder), # simulate read SeedQR; ret val is ignored
|
||||
FlowStep(seed_views.SeedFinalizeView, button_data_selection=seed_views.SeedFinalizeView.FINALIZE),
|
||||
FlowStep(seed_views.SeedOptionsView, button_data_selection=seed_views.SeedOptionsView.SIGN_MESSAGE),
|
||||
FlowStep(scan_views.ScanView, before_run=load_standard_message_into_decoder), # simulate read message QR; ret val is ignored
|
||||
FlowStep(seed_views.SeedSignMessageStartView, is_redirect=True),
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, before_run=inject_mesage_as_paged_message, screen_return_value=0),
|
||||
FlowStep(seed_views.SeedSignMessageConfirmAddressView, screen_return_value=0),
|
||||
FlowStep(seed_views.SeedSignMessageSignedMessageQRView, screen_return_value=0),
|
||||
FlowStep(MainMenuView),
|
||||
])
|
||||
|
||||
# Scenario 3: Load a long, multipage message
|
||||
self.run_sequence([
|
||||
FlowStep(MainMenuView, button_data_selection=MainMenuView.SCAN),
|
||||
FlowStep(scan_views.ScanView, before_run=load_multipage_message_into_decoder), # simulate read message QR; ret val is ignored
|
||||
FlowStep(seed_views.SeedSignMessageStartView, is_redirect=True),
|
||||
FlowStep(seed_views.SeedSelectSeedView, button_data_selection=seed_views.SeedSelectSeedView.SCAN_SEED),
|
||||
FlowStep(scan_views.ScanView, before_run=load_seed_into_decoder), # simulate read SeedQR; ret val is ignored
|
||||
FlowStep(seed_views.SeedFinalizeView, button_data_selection=seed_views.SeedFinalizeView.FINALIZE),
|
||||
FlowStep(seed_views.SeedOptionsView, is_redirect=True),
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, before_run=inject_mesage_as_paged_message, screen_return_value=0), # page 1/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 2/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 3/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 4/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 5/5
|
||||
|
||||
# Arrive at the address confirmation, then go backwards to re-review the paged message
|
||||
FlowStep(seed_views.SeedSignMessageConfirmAddressView, screen_return_value=RET_CODE__BACK_BUTTON), # then back to page 5/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=RET_CODE__BACK_BUTTON), # back to page 4/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=RET_CODE__BACK_BUTTON), # back to page 3/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=RET_CODE__BACK_BUTTON), # back to page 2/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=RET_CODE__BACK_BUTTON), # back to page 1/5
|
||||
|
||||
# Now proceed forward again to the end
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 1/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 2/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 3/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 4/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmMessageView, screen_return_value=0), # page 5/5
|
||||
FlowStep(seed_views.SeedSignMessageConfirmAddressView, screen_return_value=0),
|
||||
FlowStep(seed_views.SeedSignMessageSignedMessageQRView, screen_return_value=0),
|
||||
FlowStep(MainMenuView),
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user