Large refactor to add ButtonOption and mark_for_translation

This commit is contained in:
kdmukai
2024-11-03 06:55:54 -06:00
parent e4c4cb4edf
commit d412be2080
20 changed files with 397 additions and 407 deletions
+6 -23
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: seedsigner 0.8.5\n" "Project-Id-Version: seedsigner 0.8.5\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-11-02 12:38-0500\n" "POT-Creation-Date: 2024-11-02 16:48-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -151,9 +151,6 @@ msgstr[1] ""
msgid "{} change" msgid "{} change"
msgstr "" msgstr ""
#. First variable is either "Multisig" or the fingerprint for single sig;
#. Second is "Change" or "Addr" (change vs receive addr); Third is the address
#. index number (e.g. your #4 receive addr).
#: src/seedsigner/gui/screens/psbt_screens.py #: src/seedsigner/gui/screens/psbt_screens.py
#: src/seedsigner/models/settings_definition.py #: src/seedsigner/models/settings_definition.py
#: src/seedsigner/views/seed_views.py #: src/seedsigner/views/seed_views.py
@@ -164,6 +161,7 @@ msgstr ""
msgid "Change" msgid "Change"
msgstr "" msgstr ""
#. Abbreviation for receive address
#: src/seedsigner/gui/screens/psbt_screens.py #: src/seedsigner/gui/screens/psbt_screens.py
msgid "Addr" msgid "Addr"
msgstr "" msgstr ""
@@ -263,6 +261,7 @@ msgstr ""
#. a label for the shortened Key-id of a BIP-32 master HD wallet #. a label for the shortened Key-id of a BIP-32 master HD wallet
#: src/seedsigner/gui/screens/seed_screens.py #: src/seedsigner/gui/screens/seed_screens.py
#: src/seedsigner/gui/screens/tools_screens.py #: src/seedsigner/gui/screens/tools_screens.py
#: src/seedsigner/views/seed_views.py
msgid "fingerprint" msgid "fingerprint"
msgstr "" msgstr ""
@@ -817,7 +816,7 @@ msgid ""
"addresses." "addresses."
msgstr "" msgstr ""
#: src/seedsigner/views/psbt_views.py src/seedsigner/views/view.py #: src/seedsigner/views/psbt_views.py
msgid "Continue" msgid "Continue"
msgstr "" msgstr ""
@@ -1295,11 +1294,6 @@ msgstr ""
msgid "Return to PSBT" msgid "Return to PSBT"
msgstr "" msgstr ""
#. Inserts mainnet/testnet/regtest and derivation path
#: src/seedsigner/views/seed_views.py
msgid "Current network setting ({}) doesn't match {}"
msgstr ""
#: src/seedsigner/views/seed_views.py #: src/seedsigner/views/seed_views.py
msgid "Signing messages for custom derivation paths not supported" msgid "Signing messages for custom derivation paths not supported"
msgstr "" msgstr ""
@@ -1470,9 +1464,9 @@ msgstr ""
msgid "Change Setting" msgid "Change Setting"
msgstr "" msgstr ""
#. Inserts mainnet/testnet/regtest #. Inserts mainnet/testnet/regtest and derivation path
#: src/seedsigner/views/view.py #: src/seedsigner/views/view.py
msgid "Current network setting ({}) doesn't match current action." msgid "Current network setting ({}) doesn't match {}."
msgstr "" msgstr ""
#: src/seedsigner/views/view.py #: src/seedsigner/views/view.py
@@ -1493,14 +1487,3 @@ msgstr ""
msgid "Option Disabled" msgid "Option Disabled"
msgstr "" msgstr ""
#: src/seedsigner/views/view.py
msgid "Security Tip"
msgstr ""
#: src/seedsigner/views/view.py
msgid ""
"For maximum security,\n"
"remove the MicroSD card\n"
"before continuing."
msgstr ""
+1
View File
@@ -1,4 +1,5 @@
[extract_messages] [extract_messages]
keywords = _ _mft mark_for_translation ButtonOption
add_comments = TRANSLATOR_NOTE: add_comments = TRANSLATOR_NOTE:
strip_comments = yes strip_comments = yes
add_location = file add_location = file
+14 -5
View File
@@ -11,7 +11,7 @@ from seedsigner.gui.components import (BtcAmount, Icon, FontAwesomeIconConstants
from seedsigner.gui.renderer import Renderer from seedsigner.gui.renderer import Renderer
from seedsigner.models.threads import BaseThread from seedsigner.models.threads import BaseThread
from .screen import ButtonListScreen from .screen import ButtonListScreen, ButtonOption
@@ -31,7 +31,7 @@ class PSBTOverviewScreen(ButtonListScreen):
# Customize defaults # Customize defaults
self.title = _("Review PSBT") self.title = _("Review PSBT")
self.is_bottom_list = True self.is_bottom_list = True
self.button_data = [_("Review Details")] self.button_data = [ButtonOption("Review Details")]
# This screen can take a while to load while parsing the PSBT # This screen can take a while to load while parsing the PSBT
self.show_loading_screen = True self.show_loading_screen = True
@@ -479,7 +479,7 @@ class PSBTMathScreen(ButtonListScreen):
def __post_init__(self): def __post_init__(self):
# Customize defaults # Customize defaults
self.title = _("PSBT Math") self.title = _("PSBT Math")
self.button_data = [_("Review Recipients")] self.button_data = [ButtonOption("Review Recipients")]
self.is_bottom_list = True self.is_bottom_list = True
super().__post_init__() super().__post_init__()
@@ -675,9 +675,18 @@ class PSBTChangeDetailsScreen(ButtonListScreen):
)) ))
screen_y = self.components[-1].screen_y + self.components[-1].height + 2*GUIConstants.COMPONENT_PADDING screen_y = self.components[-1].screen_y + self.components[-1].height + 2*GUIConstants.COMPONENT_PADDING
change_type = _("Multisig") if self.is_multisig else self.fingerprint
if self.is_change_derivation_path :
addr_type = _("Change")
else:
# TRANSLATOR_NOTE: Abbreviation for receive address
addr_type = _("Addr")
value_text = "{}: {} #{}".format(change_type, addr_type, self.derivation_path_addr_index)
self.components.append(IconTextLine( self.components.append(IconTextLine(
# TRANSLATOR_NOTE: First variable is either "Multisig" or the fingerprint for single sig; Second is "Change" or "Addr" (change vs receive addr); Third is the address index number (e.g. your #4 receive addr). value_text=value_text,
value_text="""{}: {} #{}""".format(_("Multisig") if self.is_multisig else self.fingerprint, _("Change") if self.is_change_derivation_path else _("Addr"), self.derivation_path_addr_index),
icon_name=SeedSignerIconConstants.FINGERPRINT, icon_name=SeedSignerIconConstants.FINGERPRINT,
icon_color=GUIConstants.INFO_COLOR, icon_color=GUIConstants.INFO_COLOR,
is_text_centered=False, is_text_centered=False,
+61 -23
View File
@@ -5,6 +5,7 @@ from gettext import gettext as _
from PIL import Image, ImageDraw, ImageColor from PIL import Image, ImageDraw, ImageColor
from typing import Any, List, Tuple from typing import Any, List, Tuple
from seedsigner.helpers.l10n import mark_for_translation as _mft
from seedsigner.gui.components import (GUIConstants, from seedsigner.gui.components import (GUIConstants,
BaseComponent, Button, Icon, IconButton, LargeIconButton, BaseComponent, Button, Icon, IconButton, LargeIconButton,
SeedSignerIconConstants, TopNav, TextArea, load_image) SeedSignerIconConstants, TopNav, TextArea, load_image)
@@ -252,9 +253,23 @@ class BaseTopNavScreen(BaseScreen):
@dataclass
class ButtonOption:
"""
Note: The babel config in setup.cfg will extract the `button_label` string for translation
"""
button_label: str
icon_name: str = None
icon_color: str = None
right_icon_name: str = None
button_label_color: str = None
return_data: Any = None
@dataclass @dataclass
class ButtonListScreen(BaseTopNavScreen): class ButtonListScreen(BaseTopNavScreen):
button_data: list = None # list can be a mix of str or tuple(label: str, icon_name: str) button_data: list[ButtonOption] = None
selected_button: int = 0 selected_button: int = 0
is_button_text_centered: bool = True is_button_text_centered: bool = True
is_bottom_list: bool = False is_bottom_list: bool = False
@@ -295,26 +310,38 @@ class ButtonListScreen(BaseTopNavScreen):
self.has_scroll_arrows = True self.has_scroll_arrows = True
self.buttons: List[Button] = [] self.buttons: List[Button] = []
for i, button_label in enumerate(self.button_data): for i, button_option in enumerate(self.button_data):
icon_name = None icon_name = None
icon_color = None icon_color = None
right_icon_name = None right_icon_name = None
button_label_color = None button_label_color = None
# TODO: Define an actual class for button_data? if type(button_option) == ButtonOption:
if type(button_label) == tuple: button_label = button_option.button_label
if len(button_label) == 2: icon_name = button_option.icon_name
(button_label, icon_name) = button_label icon_color = button_option.icon_color
icon_color = GUIConstants.BUTTON_FONT_COLOR right_icon_name = button_option.right_icon_name
button_label_color = button_option.button_label_color
else:
raise Exception("Refactor needed!")
elif len(button_label) == 3: # # TODO: Complete refactor away from str|tuple to ButtonOption
(button_label, icon_name, icon_color) = button_label # elif type(button_option) == str:
# button_label = button_option
# elif type(button_option) == tuple:
# if len(button_option) == 2:
# (button_label, icon_name) = button_option
# icon_color = GUIConstants.BUTTON_FONT_COLOR
elif len(button_label) == 4: # elif len(button_option) == 3:
(button_label, icon_name, icon_color, button_label_color) = button_label # (button_label, icon_name, icon_color) = button_option
elif len(button_label) == 5: # elif len(button_option) == 4:
(button_label, icon_name, icon_color, button_label_color, right_icon_name) = button_label # (button_label, icon_name, icon_color, button_label_color) = button_option
# elif len(button_option) == 5:
# (button_label, icon_name, icon_color, button_label_color, right_icon_name) = button_option
button_kwargs = dict( button_kwargs = dict(
text=_(button_label), # Wrap here for just-in-time translations text=_(button_label), # Wrap here for just-in-time translations
@@ -547,11 +574,20 @@ class LargeButtonScreen(BaseTopNavScreen):
button_start_y = self.top_nav.height + int((self.canvas_height - (self.top_nav.height + GUIConstants.COMPONENT_PADDING) - (2 * button_height) - GUIConstants.COMPONENT_PADDING) / 2) button_start_y = self.top_nav.height + int((self.canvas_height - (self.top_nav.height + GUIConstants.COMPONENT_PADDING) - (2 * button_height) - GUIConstants.COMPONENT_PADDING) / 2)
self.buttons = [] self.buttons = []
for i, button_label in enumerate(self.button_data): for i, button_option in enumerate(self.button_data):
if type(button_label) == tuple: if type(button_option) == ButtonOption:
(button_label, icon_name) = button_label button_label = button_option.button_label
icon_name = button_option.icon_name
else: else:
icon_name = None raise Exception("Refactor needed!")
# elif type(button_option) == str:
# button_label = button_option
# icon_name = None
# elif type(button_option) == tuple:
# (button_label, icon_name) = button_option
# else:
# print(type(button_option))
if i % 2 == 0: if i % 2 == 0:
button_start_x = GUIConstants.EDGE_PADDING button_start_x = GUIConstants.EDGE_PADDING
@@ -848,18 +884,20 @@ class QRDisplayScreen(BaseScreen):
@dataclass @dataclass
class LargeIconStatusScreen(ButtonListScreen): class LargeIconStatusScreen(ButtonListScreen):
title: str = _("Success!") title: str = _mft("Success!")
status_icon_name: str = SeedSignerIconConstants.SUCCESS status_icon_name: str = SeedSignerIconConstants.SUCCESS
status_icon_size: int = GUIConstants.ICON_PRIMARY_SCREEN_SIZE status_icon_size: int = GUIConstants.ICON_PRIMARY_SCREEN_SIZE
status_color: str = GUIConstants.SUCCESS_COLOR status_color: str = GUIConstants.SUCCESS_COLOR
status_headline: str = None status_headline: str = None
text: str = "" # The body text of the screen text: str = "" # The body text of the screen
text_edge_padding: int = GUIConstants.EDGE_PADDING text_edge_padding: int = GUIConstants.EDGE_PADDING
button_data: list = field(default_factory=lambda: [_("OK")]) button_data: list = None
allow_text_overflow: bool = False allow_text_overflow: bool = False
def __post_init__(self): def __post_init__(self):
if not self.button_data:
self.button_data = [ButtonOption("OK")]
self.is_bottom_list = True self.is_bottom_list = True
super().__post_init__() super().__post_init__()
@@ -971,17 +1009,17 @@ class WarningEdgesMixin:
@dataclass @dataclass
class WarningScreen(WarningEdgesMixin, LargeIconStatusScreen): class WarningScreen(WarningEdgesMixin, LargeIconStatusScreen):
title: str = _("Caution") title: str = _mft("Caution")
status_icon_name: str = SeedSignerIconConstants.WARNING status_icon_name: str = SeedSignerIconConstants.WARNING
status_color: str = "yellow" status_color: str = "yellow"
status_headline: str = _("Privacy Leak!") # The colored text under the alert icon status_headline: str = _mft("Privacy Leak!") # The colored text under the alert icon
button_data: list = field(default_factory=lambda: [_("I Understand")]) button_data: list = field(default_factory=lambda: [ButtonOption("I Understand")])
@dataclass @dataclass
class DireWarningScreen(WarningScreen): class DireWarningScreen(WarningScreen):
status_headline: str = _("Classified Info!") # The colored text under the alert icon status_headline: str = _mft("Classified Info!") # The colored text under the alert icon
status_color: str = GUIConstants.DIRE_WARNING_COLOR status_color: str = GUIConstants.DIRE_WARNING_COLOR
+6 -5
View File
@@ -11,7 +11,7 @@ from seedsigner.gui.renderer import Renderer
from seedsigner.helpers.qr import QR from seedsigner.helpers.qr import QR
from seedsigner.models.threads import BaseThread, ThreadsafeCounter from seedsigner.models.threads import BaseThread, ThreadsafeCounter
from .screen import RET_CODE__BACK_BUTTON, BaseScreen, BaseTopNavScreen, ButtonListScreen, KeyboardScreen, WarningEdgesMixin from .screen import RET_CODE__BACK_BUTTON, BaseScreen, BaseTopNavScreen, ButtonListScreen, ButtonOption, KeyboardScreen, WarningEdgesMixin
from ..components import (Button, FontAwesomeIconConstants, Fonts, FormattedAddress, IconButton, from ..components import (Button, FontAwesomeIconConstants, Fonts, FormattedAddress, IconButton,
IconTextLine, SeedSignerIconConstants, TextArea, GUIConstants, reflow_text_into_pages) IconTextLine, SeedSignerIconConstants, TextArea, GUIConstants, reflow_text_into_pages)
@@ -607,7 +607,7 @@ class SeedExportXpubDetailsScreen(WarningEdgesMixin, ButtonListScreen):
def __post_init__(self): def __post_init__(self):
# Programmatically set up other args # Programmatically set up other args
self.button_data = [_("Export Xpub")] self.button_data = [ButtonOption("Export Xpub")]
self.title = _("Xpub Details") self.title = _("Xpub Details")
# Initialize the base class # Initialize the base class
@@ -1138,7 +1138,8 @@ class SeedTranscribeSeedQRWholeQRScreen(WarningEdgesMixin, ButtonListScreen):
def __post_init__(self): def __post_init__(self):
self.title = _("Transcribe SeedQR") self.title = _("Transcribe SeedQR")
# TRANSLATOR_NOTE: Refers to the QR code size: 21x21, 25x25, or 29x29 # TRANSLATOR_NOTE: Refers to the QR code size: 21x21, 25x25, or 29x29
self.button_data = [_("Begin {}x{}").format(self.num_modules, self.num_modules)] button_label = _("Begin {}x{}").format(self.num_modules, self.num_modules)
self.button_data = [ButtonOption(button_label)]
self.is_bottom_list = True self.is_bottom_list = True
self.status_color = GUIConstants.DIRE_WARNING_COLOR self.status_color = GUIConstants.DIRE_WARNING_COLOR
super().__post_init__() super().__post_init__()
@@ -1564,7 +1565,7 @@ class SeedSignMessageConfirmMessageScreen(ButtonListScreen):
self.title = f"""Message (pt {self.page_num + 1}/{len(self.sign_message_data["paged_message"])})""" self.title = f"""Message (pt {self.page_num + 1}/{len(self.sign_message_data["paged_message"])})"""
self.is_bottom_list = True self.is_bottom_list = True
self.is_button_text_centered = True self.is_button_text_centered = True
self.button_data = [_("Next")] self.button_data = [ButtonOption("Next")]
super().__post_init__() super().__post_init__()
message_display = TextArea( message_display = TextArea(
@@ -1586,7 +1587,7 @@ class SeedSignMessageConfirmAddressScreen(ButtonListScreen):
self.title = _("Confirm Address") self.title = _("Confirm Address")
self.is_bottom_list = True self.is_bottom_list = True
self.is_button_text_centered = True self.is_button_text_centered = True
self.button_data = [_("Sign Message")] self.button_data = [ButtonOption("Sign Message")]
super().__post_init__() super().__post_init__()
derivation_path_display = IconTextLine( derivation_path_display = IconTextLine(
@@ -5,9 +5,10 @@ from gettext import gettext as _
from PIL.ImageOps import autocontrast from PIL.ImageOps import autocontrast
from typing import List from typing import List
from seedsigner.helpers.l10n import mark_for_translation as _mft
from seedsigner.gui.components import Button, CheckboxButton, CheckedSelectionButton, FontAwesomeIconConstants, Fonts, GUIConstants, Icon, IconButton, IconTextLine, TextArea from seedsigner.gui.components import Button, CheckboxButton, CheckedSelectionButton, FontAwesomeIconConstants, Fonts, GUIConstants, Icon, IconButton, IconTextLine, TextArea
from seedsigner.gui.screens.scan_screens import ScanScreen from seedsigner.gui.screens.scan_screens import ScanScreen
from seedsigner.gui.screens.screen import BaseScreen, BaseTopNavScreen, ButtonListScreen from seedsigner.gui.screens.screen import BaseScreen, BaseTopNavScreen, ButtonListScreen, ButtonOption
from seedsigner.hardware.buttons import HardwareButtonsConstants from seedsigner.hardware.buttons import HardwareButtonsConstants
from seedsigner.hardware.camera import Camera from seedsigner.hardware.camera import Camera
from seedsigner.models.settings import SettingsConstants from seedsigner.models.settings import SettingsConstants
@@ -309,13 +310,13 @@ class DonateScreen(BaseTopNavScreen):
@dataclass @dataclass
class SettingsQRConfirmationScreen(ButtonListScreen): class SettingsQRConfirmationScreen(ButtonListScreen):
config_name: str = None config_name: str = None
title: str = _("Settings QR") title: str = _mft("Settings QR")
status_message: str = _("Settings updated...") status_message: str = _mft("Settings updated...")
is_bottom_list: bool = True is_bottom_list: bool = True
def __post_init__(self): def __post_init__(self):
# Customize defaults # Customize defaults
self.button_data = [_("Home")] self.button_data = [ButtonOption("Home")]
self.show_back_button = False self.show_back_button = False
super().__post_init__() super().__post_init__()
+1 -1
View File
@@ -50,7 +50,7 @@ def get_standard_derivation_path(network: str = SettingsConstants.MAINNET, walle
elif script_type == SettingsConstants.NATIVE_SEGWIT: elif script_type == SettingsConstants.NATIVE_SEGWIT:
return f"m/48'/{network_path}/0'/2'" return f"m/48'/{network_path}/0'/2'"
elif script_type == SettingsConstants.TAPROOT: elif script_type == SettingsConstants.TAPROOT:
raise Exception("Taproot multisig/musig not yet supported") raise Exception("Taproot multisig not yet supported")
else: else:
raise Exception("Unexpected script type") raise Exception("Unexpected script type")
else: else:
+3
View File
@@ -0,0 +1,3 @@
def mark_for_translation(message: str) -> str:
# Wraps the target string literal for translation but does NOT return the translated string.
return message
+58 -58
View File
@@ -1,7 +1,7 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, List from typing import Any, List
from gettext import gettext as _ from seedsigner.helpers.l10n import mark_for_translation as _mft
class SettingsConstants: class SettingsConstants:
@@ -11,25 +11,25 @@ class SettingsConstants:
OPTION__PROMPT = "P" OPTION__PROMPT = "P"
OPTION__REQUIRED = "R" OPTION__REQUIRED = "R"
OPTIONS__ENABLED_DISABLED = [ OPTIONS__ENABLED_DISABLED = [
(OPTION__ENABLED, _("Enabled")), (OPTION__ENABLED, _mft("Enabled")),
(OPTION__DISABLED, _("Disabled")), (OPTION__DISABLED, _mft("Disabled")),
] ]
OPTIONS__ONLY_DISABLED = [ OPTIONS__ONLY_DISABLED = [
(OPTION__DISABLED, _("Disabled")), (OPTION__DISABLED, _mft("Disabled")),
] ]
OPTIONS__PROMPT_REQUIRED_DISABLED = [ OPTIONS__PROMPT_REQUIRED_DISABLED = [
(OPTION__PROMPT, _("Prompt")), (OPTION__PROMPT, _mft("Prompt")),
(OPTION__REQUIRED, _("Required")), (OPTION__REQUIRED, _mft("Required")),
(OPTION__DISABLED, _("Disabled")), (OPTION__DISABLED, _mft("Disabled")),
] ]
OPTIONS__ENABLED_DISABLED_REQUIRED = OPTIONS__ENABLED_DISABLED +[ OPTIONS__ENABLED_DISABLED_REQUIRED = OPTIONS__ENABLED_DISABLED +[
(OPTION__REQUIRED, _("Required")), (OPTION__REQUIRED, _mft("Required")),
] ]
OPTIONS__ENABLED_DISABLED_PROMPT = OPTIONS__ENABLED_DISABLED + [ OPTIONS__ENABLED_DISABLED_PROMPT = OPTIONS__ENABLED_DISABLED + [
(OPTION__PROMPT, _("Prompt")), (OPTION__PROMPT, _mft("Prompt")),
] ]
ALL_OPTIONS = OPTIONS__ENABLED_DISABLED_PROMPT + [ ALL_OPTIONS = OPTIONS__ENABLED_DISABLED_PROMPT + [
(OPTION__REQUIRED, _("Required")), (OPTION__REQUIRED, _mft("Required")),
] ]
# User-facing selection options # User-facing selection options
@@ -77,10 +77,10 @@ class SettingsConstants:
BTC_DENOMINATION__THRESHOLD = "thr" BTC_DENOMINATION__THRESHOLD = "thr"
BTC_DENOMINATION__BTCSATSHYBRID = "hyb" BTC_DENOMINATION__BTCSATSHYBRID = "hyb"
ALL_BTC_DENOMINATIONS = [ ALL_BTC_DENOMINATIONS = [
(BTC_DENOMINATION__BTC, _("BTC")), (BTC_DENOMINATION__BTC, _mft("BTC")),
(BTC_DENOMINATION__SATS, _("sats")), (BTC_DENOMINATION__SATS, _mft("sats")),
(BTC_DENOMINATION__THRESHOLD, _("Threshold at 0.01")), (BTC_DENOMINATION__THRESHOLD, _mft("Threshold at 0.01")),
(BTC_DENOMINATION__BTCSATSHYBRID, _("BTC | sats hybrid")), (BTC_DENOMINATION__BTCSATSHYBRID, _mft("BTC | sats hybrid")),
] ]
CAMERA_ROTATION__0 = 0 CAMERA_ROTATION__0 = 0
@@ -88,10 +88,10 @@ class SettingsConstants:
CAMERA_ROTATION__180 = 180 CAMERA_ROTATION__180 = 180
CAMERA_ROTATION__270 = 270 CAMERA_ROTATION__270 = 270
ALL_CAMERA_ROTATIONS = [ ALL_CAMERA_ROTATIONS = [
(CAMERA_ROTATION__0, _("0°")), (CAMERA_ROTATION__0, _mft("0°")),
(CAMERA_ROTATION__90, _("90°")), (CAMERA_ROTATION__90, _mft("90°")),
(CAMERA_ROTATION__180, _("180°")), (CAMERA_ROTATION__180, _mft("180°")),
(CAMERA_ROTATION__270, _("270°")), (CAMERA_ROTATION__270, _mft("270°")),
] ]
# QR code constants # QR code constants
@@ -99,11 +99,11 @@ class SettingsConstants:
DENSITY__MEDIUM = "M" DENSITY__MEDIUM = "M"
DENSITY__HIGH = "H" DENSITY__HIGH = "H"
# TRANSLATOR_NOTE: QR code density option: Low, Medium, High # TRANSLATOR_NOTE: QR code density option: Low, Medium, High
density_low = _("Low") density_low = _mft("Low")
# TRANSLATOR_NOTE: QR code density option: Low, Medium, High # TRANSLATOR_NOTE: QR code density option: Low, Medium, High
density_medium = _("Medium") density_medium = _mft("Medium")
# TRANSLATOR_NOTE: QR code density option: Low, Medium, High # TRANSLATOR_NOTE: QR code density option: Low, Medium, High
density_high = _("High") density_high = _mft("High")
ALL_DENSITIES = [ ALL_DENSITIES = [
(DENSITY__LOW, density_low), (DENSITY__LOW, density_low),
(DENSITY__MEDIUM, density_medium), (DENSITY__MEDIUM, density_medium),
@@ -115,9 +115,9 @@ class SettingsConstants:
TESTNET = "T" TESTNET = "T"
REGTEST = "R" REGTEST = "R"
ALL_NETWORKS = [ ALL_NETWORKS = [
(MAINNET, _("Mainnet")), (MAINNET, _mft("Mainnet")),
(TESTNET, _("Testnet")), (TESTNET, _mft("Testnet")),
(REGTEST, _("Regtest")) (REGTEST, _mft("Regtest"))
] ]
@classmethod @classmethod
@@ -130,14 +130,14 @@ class SettingsConstants:
if network == SettingsConstants.REGTEST: if network == SettingsConstants.REGTEST:
return "regtest" return "regtest"
PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT = _("Store Settings on SD card") PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT = _mft("Store Settings on SD card")
PERSISTENT_SETTINGS__SD_REMOVED__HELP_TEXT = _("Insert SD card to enable") PERSISTENT_SETTINGS__SD_REMOVED__HELP_TEXT = _mft("Insert SD card to enable")
SINGLE_SIG = "ss" SINGLE_SIG = "ss"
MULTISIG = "ms" MULTISIG = "ms"
ALL_SIG_TYPES = [ ALL_SIG_TYPES = [
(SINGLE_SIG, _("Single Sig")), (SINGLE_SIG, _mft("Single Sig")),
(MULTISIG, _("Multisig")), (MULTISIG, _mft("Multisig")),
] ]
LEGACY_P2PKH = "leg" LEGACY_P2PKH = "leg"
@@ -146,11 +146,11 @@ class SettingsConstants:
TAPROOT = "tr" TAPROOT = "tr"
CUSTOM_DERIVATION = "cus" CUSTOM_DERIVATION = "cus"
ALL_SCRIPT_TYPES = [ ALL_SCRIPT_TYPES = [
(NATIVE_SEGWIT, _("Native Segwit")), (NATIVE_SEGWIT, _mft("Native Segwit")),
(NESTED_SEGWIT, _("Nested Segwit")), (NESTED_SEGWIT, _mft("Nested Segwit")),
(LEGACY_P2PKH, _("Legacy")), (LEGACY_P2PKH, _mft("Legacy")),
(TAPROOT, _("Taproot")), (TAPROOT, _mft("Taproot")),
(CUSTOM_DERIVATION, _("Custom Derivation")), (CUSTOM_DERIVATION, _mft("Custom Derivation")),
] ]
WORDLIST_LANGUAGE__ENGLISH = "en" WORDLIST_LANGUAGE__ENGLISH = "en"
@@ -237,9 +237,9 @@ class SettingsConstants:
ELECTRUM_PBKDF2_ROUNDS=2048 ELECTRUM_PBKDF2_ROUNDS=2048
# Label strings # Label strings
LABEL__BIP39_PASSPHRASE = _("BIP-39 Passphrase") LABEL__BIP39_PASSPHRASE = _mft("BIP-39 Passphrase")
# TRANSLATOR_NOTE: Terminology used by Electrum seeds; equivalent to bip39 passphrase # TRANSLATOR_NOTE: Terminology used by Electrum seeds; equivalent to bip39 passphrase
custom_extension = _("Custom Extension") custom_extension = _mft("Custom Extension")
LABEL__CUSTOM_EXTENSION = custom_extension LABEL__CUSTOM_EXTENSION = custom_extension
@@ -311,7 +311,7 @@ class SettingsEntry:
option_value = option option_value = option
display_name = option display_name = option
if option_value == value: if option_value == value:
return _(display_name) return _mft(display_name)
def get_selection_option_value_by_display_name(self, display_name: str): def get_selection_option_value_by_display_name(self, display_name: str):
@@ -380,7 +380,7 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM,
attr_name=SettingsConstants.SETTING__LOCALE, attr_name=SettingsConstants.SETTING__LOCALE,
abbreviated_name="lang", abbreviated_name="lang",
display_name=_("Language"), display_name=_mft("Language"),
type=SettingsConstants.TYPE__SELECT_1, type=SettingsConstants.TYPE__SELECT_1,
selection_options=SettingsConstants.ALL_LOCALES, selection_options=SettingsConstants.ALL_LOCALES,
default_value=SettingsConstants.LOCALE__ENGLISH), default_value=SettingsConstants.LOCALE__ENGLISH),
@@ -389,7 +389,7 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM,
attr_name=SettingsConstants.SETTING__WORDLIST_LANGUAGE, attr_name=SettingsConstants.SETTING__WORDLIST_LANGUAGE,
abbreviated_name="wordlist_lang", abbreviated_name="wordlist_lang",
display_name=_("Mnemonic language"), display_name=_mft("Mnemonic language"),
type=SettingsConstants.TYPE__SELECT_1, type=SettingsConstants.TYPE__SELECT_1,
visibility=SettingsConstants.VISIBILITY__HIDDEN, visibility=SettingsConstants.VISIBILITY__HIDDEN,
selection_options=SettingsConstants.ALL_WORDLIST_LANGUAGES, selection_options=SettingsConstants.ALL_WORDLIST_LANGUAGES,
@@ -398,14 +398,14 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM,
attr_name=SettingsConstants.SETTING__PERSISTENT_SETTINGS, attr_name=SettingsConstants.SETTING__PERSISTENT_SETTINGS,
abbreviated_name="persistent", abbreviated_name="persistent",
display_name=_("Persistent settings"), display_name=_mft("Persistent settings"),
help_text=SettingsConstants.PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT, help_text=SettingsConstants.PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT,
default_value=SettingsConstants.OPTION__DISABLED), default_value=SettingsConstants.OPTION__DISABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__WALLET, SettingsEntry(category=SettingsConstants.CATEGORY__WALLET,
attr_name=SettingsConstants.SETTING__COORDINATORS, attr_name=SettingsConstants.SETTING__COORDINATORS,
abbreviated_name="coords", abbreviated_name="coords",
display_name=_("Coordinator software"), display_name=_mft("Coordinator software"),
type=SettingsConstants.TYPE__MULTISELECT, type=SettingsConstants.TYPE__MULTISELECT,
selection_options=SettingsConstants.ALL_COORDINATORS, selection_options=SettingsConstants.ALL_COORDINATORS,
default_value=[ default_value=[
@@ -418,7 +418,7 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM,
attr_name=SettingsConstants.SETTING__BTC_DENOMINATION, attr_name=SettingsConstants.SETTING__BTC_DENOMINATION,
abbreviated_name="denom", abbreviated_name="denom",
display_name=_("Denomination display"), display_name=_mft("Denomination display"),
type=SettingsConstants.TYPE__SELECT_1, type=SettingsConstants.TYPE__SELECT_1,
selection_options=SettingsConstants.ALL_BTC_DENOMINATIONS, selection_options=SettingsConstants.ALL_BTC_DENOMINATIONS,
default_value=SettingsConstants.BTC_DENOMINATION__THRESHOLD), default_value=SettingsConstants.BTC_DENOMINATION__THRESHOLD),
@@ -427,7 +427,7 @@ class SettingsDefinition:
# Advanced options # Advanced options
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__NETWORK, attr_name=SettingsConstants.SETTING__NETWORK,
display_name=_("Bitcoin network"), display_name=_mft("Bitcoin network"),
type=SettingsConstants.TYPE__SELECT_1, type=SettingsConstants.TYPE__SELECT_1,
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
selection_options=SettingsConstants.ALL_NETWORKS, selection_options=SettingsConstants.ALL_NETWORKS,
@@ -435,7 +435,7 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__QR_DENSITY, attr_name=SettingsConstants.SETTING__QR_DENSITY,
display_name=_("QR code density"), display_name=_mft("QR code density"),
type=SettingsConstants.TYPE__SELECT_1, type=SettingsConstants.TYPE__SELECT_1,
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
selection_options=SettingsConstants.ALL_DENSITIES, selection_options=SettingsConstants.ALL_DENSITIES,
@@ -443,14 +443,14 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__XPUB_EXPORT, attr_name=SettingsConstants.SETTING__XPUB_EXPORT,
display_name=_("Xpub export"), display_name=_mft("Xpub export"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__ENABLED), default_value=SettingsConstants.OPTION__ENABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__SIG_TYPES, attr_name=SettingsConstants.SETTING__SIG_TYPES,
abbreviated_name="sigs", abbreviated_name="sigs",
display_name=_("Sig types"), display_name=_mft("Sig types"),
type=SettingsConstants.TYPE__MULTISELECT, type=SettingsConstants.TYPE__MULTISELECT,
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
selection_options=SettingsConstants.ALL_SIG_TYPES, selection_options=SettingsConstants.ALL_SIG_TYPES,
@@ -459,7 +459,7 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__SCRIPT_TYPES, attr_name=SettingsConstants.SETTING__SCRIPT_TYPES,
abbreviated_name="scripts", abbreviated_name="scripts",
display_name=_("Script types"), display_name=_mft("Script types"),
type=SettingsConstants.TYPE__MULTISELECT, type=SettingsConstants.TYPE__MULTISELECT,
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
selection_options=SettingsConstants.ALL_SCRIPT_TYPES, selection_options=SettingsConstants.ALL_SCRIPT_TYPES,
@@ -467,13 +467,13 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__XPUB_DETAILS, attr_name=SettingsConstants.SETTING__XPUB_DETAILS,
display_name=_("Show xpub details"), display_name=_mft("Show xpub details"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__ENABLED), default_value=SettingsConstants.OPTION__ENABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__PASSPHRASE, attr_name=SettingsConstants.SETTING__PASSPHRASE,
display_name=_("BIP-39 passphrase"), display_name=_mft("BIP-39 passphrase"),
type=SettingsConstants.TYPE__SELECT_1, type=SettingsConstants.TYPE__SELECT_1,
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
selection_options=SettingsConstants.OPTIONS__ENABLED_DISABLED_REQUIRED, selection_options=SettingsConstants.OPTIONS__ENABLED_DISABLED_REQUIRED,
@@ -482,7 +482,7 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__CAMERA_ROTATION, attr_name=SettingsConstants.SETTING__CAMERA_ROTATION,
abbreviated_name="camera", abbreviated_name="camera",
display_name=_("Camera rotation"), display_name=_mft("Camera rotation"),
type=SettingsConstants.TYPE__SELECT_1, type=SettingsConstants.TYPE__SELECT_1,
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
selection_options=SettingsConstants.ALL_CAMERA_ROTATIONS, selection_options=SettingsConstants.ALL_CAMERA_ROTATIONS,
@@ -490,14 +490,14 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__COMPACT_SEEDQR, attr_name=SettingsConstants.SETTING__COMPACT_SEEDQR,
display_name=_("Compact SeedQR"), display_name=_mft("Compact SeedQR"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__ENABLED), default_value=SettingsConstants.OPTION__ENABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__BIP85_CHILD_SEEDS, attr_name=SettingsConstants.SETTING__BIP85_CHILD_SEEDS,
abbreviated_name="bip85", abbreviated_name="bip85",
display_name=_("BIP-85 child seeds"), display_name=_mft("BIP-85 child seeds"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__DISABLED), default_value=SettingsConstants.OPTION__DISABLED),
@@ -505,40 +505,40 @@ class SettingsDefinition:
attr_name=SettingsConstants.SETTING__ELECTRUM_SEEDS, attr_name=SettingsConstants.SETTING__ELECTRUM_SEEDS,
abbreviated_name="electrum", abbreviated_name="electrum",
display_name="Electrum seeds", display_name="Electrum seeds",
help_text=_("Native Segwit only"), help_text=_mft("Native Segwit only"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__DISABLED), default_value=SettingsConstants.OPTION__DISABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__MESSAGE_SIGNING, attr_name=SettingsConstants.SETTING__MESSAGE_SIGNING,
display_name=_("Message signing"), display_name=_mft("Message signing"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__DISABLED), default_value=SettingsConstants.OPTION__DISABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__PRIVACY_WARNINGS, attr_name=SettingsConstants.SETTING__PRIVACY_WARNINGS,
abbreviated_name="priv_warn", abbreviated_name="priv_warn",
display_name=_("Show privacy warnings"), display_name=_mft("Show privacy warnings"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__ENABLED), default_value=SettingsConstants.OPTION__ENABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__DIRE_WARNINGS, attr_name=SettingsConstants.SETTING__DIRE_WARNINGS,
abbreviated_name="dire_warn", abbreviated_name="dire_warn",
display_name=_("Show dire warnings"), display_name=_mft("Show dire warnings"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__ENABLED), default_value=SettingsConstants.OPTION__ENABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__QR_BRIGHTNESS_TIPS, attr_name=SettingsConstants.SETTING__QR_BRIGHTNESS_TIPS,
display_name=_("Show QR brightness tips"), display_name=_mft("Show QR brightness tips"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__ENABLED), default_value=SettingsConstants.OPTION__ENABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__PARTNER_LOGOS, attr_name=SettingsConstants.SETTING__PARTNER_LOGOS,
abbreviated_name="partners", abbreviated_name="partners",
display_name=_("Show partner logos"), display_name=_mft("Show partner logos"),
visibility=SettingsConstants.VISIBILITY__ADVANCED, visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__ENABLED), default_value=SettingsConstants.OPTION__ENABLED),
@@ -554,7 +554,7 @@ class SettingsDefinition:
SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM,
attr_name=SettingsConstants.SETTING__QR_BRIGHTNESS, attr_name=SettingsConstants.SETTING__QR_BRIGHTNESS,
abbreviated_name="qr_brightness", abbreviated_name="qr_brightness",
display_name=_("QR background color"), display_name=_mft("QR background color"),
type=SettingsConstants.TYPE__FREE_ENTRY, type=SettingsConstants.TYPE__FREE_ENTRY,
visibility=SettingsConstants.VISIBILITY__HIDDEN, visibility=SettingsConstants.VISIBILITY__HIDDEN,
default_value=62), default_value=62),
+19 -21
View File
@@ -3,16 +3,16 @@ from gettext import gettext as _
from seedsigner.models.psbt_parser import PSBTParser from seedsigner.models.psbt_parser import PSBTParser
from seedsigner.models.settings import SettingsConstants from seedsigner.models.settings import SettingsConstants
from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants
from seedsigner.gui.screens.screen import (RET_CODE__BACK_BUTTON, ButtonListScreen, WarningScreen, DireWarningScreen, QRDisplayScreen) from seedsigner.gui.screens.screen import (RET_CODE__BACK_BUTTON, ButtonListScreen, ButtonOption, WarningScreen, DireWarningScreen, QRDisplayScreen)
from seedsigner.views.view import BackStackView, MainMenuView, NotYetImplementedView, View, Destination from seedsigner.views.view import BackStackView, MainMenuView, NotYetImplementedView, View, Destination
class PSBTSelectSeedView(View): class PSBTSelectSeedView(View):
SCAN_SEED = (_("Scan a seed"), SeedSignerIconConstants.QRCODE) SCAN_SEED = ButtonOption("Scan a seed", SeedSignerIconConstants.QRCODE)
TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD)
def run(self): def run(self):
@@ -38,7 +38,7 @@ class PSBTSelectSeedView(View):
# TRANSLATOR_NOTE: Inserts fingerprint w/"?" to indicate that this seed can't sign the current PSBT # TRANSLATOR_NOTE: Inserts fingerprint w/"?" to indicate that this seed can't sign the current PSBT
button_str = _("{} (?)").format(button_str) button_str = _("{} (?)").format(button_str)
button_data.append((button_str, SeedSignerIconConstants.FINGERPRINT)) button_data.append(ButtonOption(button_str, SeedSignerIconConstants.FINGERPRINT))
button_data.append(self.SCAN_SEED) button_data.append(self.SCAN_SEED)
button_data.append(self.TYPE_12WORD) button_data.append(self.TYPE_12WORD)
@@ -169,7 +169,7 @@ class PSBTUnsupportedScriptTypeWarningView(View):
selected_menu_num = WarningScreen( selected_menu_num = WarningScreen(
status_headline=_("Unsupported Script Type!"), status_headline=_("Unsupported Script Type!"),
text=_("PSBT has unsupported input script type, please verify your change addresses."), text=_("PSBT has unsupported input script type, please verify your change addresses."),
button_data=[_("Continue")], button_data=[ButtonOption("Continue")],
).display() ).display()
if selected_menu_num == RET_CODE__BACK_BUTTON: if selected_menu_num == RET_CODE__BACK_BUTTON:
@@ -190,7 +190,7 @@ class PSBTNoChangeWarningView(View):
# TRANSLATOR_NOTE: User will receive no change back; the inputs to this transaction are fully spent # TRANSLATOR_NOTE: User will receive no change back; the inputs to this transaction are fully spent
status_headline=_("Full Spend!"), status_headline=_("Full Spend!"),
text=_("This PSBT spends its entire input value. No change is coming back to your wallet."), text=_("This PSBT spends its entire input value. No change is coming back to your wallet."),
button_data=[_("Continue")], button_data=[ButtonOption("Continue")],
).display() ).display()
if selected_menu_num == RET_CODE__BACK_BUTTON: if selected_menu_num == RET_CODE__BACK_BUTTON:
@@ -265,10 +265,10 @@ class PSBTAddressDetailsView(View):
button_data = [] button_data = []
if self.address_num < psbt_parser.num_destinations - 1: if self.address_num < psbt_parser.num_destinations - 1:
button_data.append(_("Next Recipient")) button_data.append(ButtonOption("Next Recipient"))
else: else:
# TRANSLATOR_NOTE: Short for "Next step" # TRANSLATOR_NOTE: Short for "Next step"
button_data.append(_("Next")) button_data.append(ButtonOption("Next"))
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
PSBTAddressDetailsScreen, PSBTAddressDetailsScreen,
@@ -299,10 +299,9 @@ class PSBTAddressDetailsView(View):
class PSBTChangeDetailsView(View): class PSBTChangeDetailsView(View):
NEXT = _("Next") NEXT = ButtonOption("Next")
SKIP_VERIFICATION = _("Skip Verification") SKIP_VERIFICATION = ButtonOption("Skip Verification")
VERIFY_MULTISIG = _("Verify Multisig Change") VERIFY_MULTISIG = ButtonOption("Verify Multisig Change")
def __init__(self, change_address_num): def __init__(self, change_address_num):
super().__init__() super().__init__()
@@ -349,7 +348,7 @@ class PSBTChangeDetailsView(View):
title = _("Your Change") title = _("Your Change")
else: else:
title = _("Self-Transfer") title = _("Self-Transfer")
self.VERIFY_MULTISIG = _("Verify Multisig Addr") self.VERIFY_MULTISIG.button_label = _("Verify Multisig Addr")
# if psbt_parser.num_change_outputs > 1: # if psbt_parser.num_change_outputs > 1:
# title += f" (#{self.change_address_num + 1})" # title += f" (#{self.change_address_num + 1})"
@@ -473,7 +472,7 @@ class PSBTAddressVerificationFailedView(View):
title=title, title=title,
status_headline=_("Address Verification Failed"), status_headline=_("Address Verification Failed"),
text=text, text=text,
button_data=[_("Discard PSBT")], button_data=[ButtonOption("Discard PSBT")],
show_back_button=False, show_back_button=False,
).display() ).display()
@@ -495,8 +494,8 @@ class PSBTOpReturnView(View):
# Should not be able to get here # Should not be able to get here
raise Exception("Routing error") raise Exception("Routing error")
title = "OP_RETURN" title = _("OP_RETURN")
button_data = ["Next"] button_data = [ButtonOption("Next")]
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
PSBTOpReturnScreen, PSBTOpReturnScreen,
@@ -515,7 +514,7 @@ class PSBTOpReturnView(View):
class PSBTFinalizeView(View): class PSBTFinalizeView(View):
""" """
""" """
APPROVE_PSBT = "Approve PSBT" APPROVE_PSBT = ButtonOption("Approve PSBT")
def run(self): def run(self):
@@ -524,7 +523,6 @@ class PSBTFinalizeView(View):
psbt_parser: PSBTParser = self.controller.psbt_parser psbt_parser: PSBTParser = self.controller.psbt_parser
psbt: PSBT = self.controller.psbt psbt: PSBT = self.controller.psbt
self.APPROVE_PSBT = _("Approve PSBT")
if not psbt_parser: if not psbt_parser:
# Should not be able to get here # Should not be able to get here
@@ -573,7 +571,7 @@ class PSBTSignedQRDisplayView(View):
class PSBTSigningErrorView(View): class PSBTSigningErrorView(View):
SELECT_DIFF_SEED = _("Select Diff Seed") SELECT_DIFF_SEED = ButtonOption("Select Diff Seed")
def run(self): def run(self):
psbt_parser: PSBTParser = self.controller.psbt_parser psbt_parser: PSBTParser = self.controller.psbt_parser
+11 -11
View File
@@ -2,7 +2,7 @@ import logging
import re import re
from gettext import gettext as _ from gettext import gettext as _
from seedsigner.helpers.l10n import mark_for_translation as _mft
from seedsigner.models.settings import SettingsConstants from seedsigner.models.settings import SettingsConstants
from seedsigner.views.view import BackStackView, ErrorView, MainMenuView, NotYetImplementedView, View, Destination from seedsigner.views.view import BackStackView, ErrorView, MainMenuView, NotYetImplementedView, View, Destination
@@ -19,8 +19,8 @@ class ScanView(View):
dedicated errors when an unexpected QR type is scanned (e.g. Scan PSBT was dedicated errors when an unexpected QR type is scanned (e.g. Scan PSBT was
selected but a SeedQR was scanned). selected but a SeedQR was scanned).
""" """
instructions_text = _("Scan a QR code") instructions_text = _mft("Scan a QR code")
invalid_qr_type_message = _("QRCode not recognized or not yet supported.") invalid_qr_type_message = _mft("QRCode not recognized or not yet supported.")
def __init__(self): def __init__(self):
@@ -176,8 +176,8 @@ class ScanView(View):
class ScanPSBTView(ScanView): class ScanPSBTView(ScanView):
instructions_text = _("Scan PSBT") instructions_text = _mft("Scan PSBT")
invalid_qr_type_message = _("Expected a PSBT") invalid_qr_type_message = _mft("Expected a PSBT")
@property @property
def is_valid_qr_type(self): def is_valid_qr_type(self):
@@ -186,8 +186,8 @@ class ScanPSBTView(ScanView):
class ScanSeedQRView(ScanView): class ScanSeedQRView(ScanView):
instructions_text = _("Scan SeedQR") instructions_text = _mft("Scan SeedQR")
invalid_qr_type_message = _("Expected a SeedQR") invalid_qr_type_message = _mft("Expected a SeedQR")
@property @property
def is_valid_qr_type(self): def is_valid_qr_type(self):
@@ -196,8 +196,8 @@ class ScanSeedQRView(ScanView):
class ScanWalletDescriptorView(ScanView): class ScanWalletDescriptorView(ScanView):
instructions_text = _("Scan descriptor") instructions_text = _mft("Scan descriptor")
invalid_qr_type_message = _("Expected a wallet descriptor QR") invalid_qr_type_message = _mft("Expected a wallet descriptor QR")
@property @property
def is_valid_qr_type(self): def is_valid_qr_type(self):
@@ -206,8 +206,8 @@ class ScanWalletDescriptorView(ScanView):
class ScanAddressView(ScanView): class ScanAddressView(ScanView):
instructions_text = _("Scan address QR") instructions_text = _mft("Scan address QR")
invalid_qr_type_message = _("Expected an address QR") invalid_qr_type_message = _mft("Expected an address QR")
@property @property
def is_valid_qr_type(self): def is_valid_qr_type(self):
+93 -110
View File
@@ -10,6 +10,7 @@ from embit.descriptor import Descriptor
from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants
from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen,
WarningScreen, DireWarningScreen, seed_screens) WarningScreen, DireWarningScreen, seed_screens)
from seedsigner.gui.screens.screen import ButtonOption
from seedsigner.models.encode_qr import CompactSeedQrEncoder, GenericStaticQrEncoder, SeedQrEncoder, SpecterXPubQrEncoder, StaticXpubQrEncoder, UrXpubQrEncoder from seedsigner.models.encode_qr import CompactSeedQrEncoder, GenericStaticQrEncoder, SeedQrEncoder, SpecterXPubQrEncoder, StaticXpubQrEncoder, UrXpubQrEncoder
from seedsigner.models.qr_type import QRType from seedsigner.models.qr_type import QRType
from seedsigner.models.seed import Seed from seedsigner.models.seed import Seed
@@ -23,7 +24,7 @@ logger = logging.getLogger(__name__)
class SeedsMenuView(View): class SeedsMenuView(View):
LOAD = "Load a seed" LOAD = ButtonOption("Load a seed")
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@@ -41,8 +42,8 @@ class SeedsMenuView(View):
button_data = [] button_data = []
for seed in self.seeds: for seed in self.seeds:
button_data.append((seed["fingerprint"], SeedSignerIconConstants.FINGERPRINT)) button_data.append(ButtonOption(seed["fingerprint"], SeedSignerIconConstants.FINGERPRINT))
button_data.append(_("Load a seed")) button_data.append(self.LOAD)
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
ButtonListScreen, ButtonListScreen,
@@ -54,7 +55,7 @@ class SeedsMenuView(View):
if len(self.seeds) > 0 and selected_menu_num < len(self.seeds): if len(self.seeds) > 0 and selected_menu_num < len(self.seeds):
return Destination(SeedOptionsView, view_args={"seed_num": selected_menu_num}) return Destination(SeedOptionsView, view_args={"seed_num": selected_menu_num})
elif selected_menu_num == len(self.seeds): elif button_data[selected_menu_num] == self.LOAD:
return Destination(LoadSeedView) return Destination(LoadSeedView)
elif selected_menu_num == RET_CODE__BACK_BUTTON: elif selected_menu_num == RET_CODE__BACK_BUTTON:
@@ -70,10 +71,10 @@ class SeedSelectSeedView(View):
* `flow`: indicates which user flow is in progress during seed selection (e.g. * `flow`: indicates which user flow is in progress during seed selection (e.g.
verify single sig addr or sign message). verify single sig addr or sign message).
""" """
SCAN_SEED = (_("Scan a seed"), SeedSignerIconConstants.QRCODE) SCAN_SEED = ButtonOption("Scan a seed", SeedSignerIconConstants.QRCODE)
TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD)
def __init__(self, flow: str = None): def __init__(self, flow: str = None):
@@ -108,11 +109,7 @@ class SeedSelectSeedView(View):
button_data = [] button_data = []
for seed in seeds: for seed in seeds:
button_str = seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK)) button_str = seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK))
button_data.append(ButtonOption(button_str, SeedSignerIconConstants.FINGERPRINT, icon_color="blue"))
if seed.passphrase is not None:
# TODO: Include lock icon on right side of button
pass
button_data.append((button_str, SeedSignerIconConstants.FINGERPRINT, "blue"))
button_data.append(self.SCAN_SEED) button_data.append(self.SCAN_SEED)
button_data.append(self.TYPE_12WORD) button_data.append(self.TYPE_12WORD)
@@ -165,11 +162,11 @@ class SeedSelectSeedView(View):
Loading seeds, passphrases, etc Loading seeds, passphrases, etc
****************************************************************************""" ****************************************************************************"""
class LoadSeedView(View): class LoadSeedView(View):
SEED_QR = (_("Scan a SeedQR"), SeedSignerIconConstants.QRCODE) SEED_QR = ButtonOption("Scan a SeedQR", SeedSignerIconConstants.QRCODE)
TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD)
CREATE = (_(" Create a seed"), SeedSignerIconConstants.PLUS) CREATE = ButtonOption(" Create a seed", SeedSignerIconConstants.PLUS)
def run(self): def run(self):
button_data = [ button_data = [
@@ -274,8 +271,8 @@ class SeedMnemonicEntryView(View):
class SeedMnemonicInvalidView(View): class SeedMnemonicInvalidView(View):
EDIT = _("Review & Edit") EDIT = ButtonOption("Review & Edit")
DISCARD = (_("Discard"), None, None, "red") DISCARD = ButtonOption("Discard", button_label_color="red")
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@@ -303,8 +300,8 @@ class SeedMnemonicInvalidView(View):
class SeedFinalizeView(View): class SeedFinalizeView(View):
FINALIZE = _("Done") FINALIZE = ButtonOption("Done")
PASSPHRASE = _("BIP-39 Passphrase") PASSPHRASE = ButtonOption("BIP-39 Passphrase")
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@@ -327,9 +324,9 @@ class SeedFinalizeView(View):
def run(self): def run(self):
button_data = [self.FINALIZE] button_data = [self.FINALIZE]
passphrase_button = self.seed.passphrase_label self.PASSPHRASE.button_label = self.seed.passphrase_label
if self.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) != SettingsConstants.OPTION__DISABLED: if self.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) != SettingsConstants.OPTION__DISABLED:
button_data.append(passphrase_button) button_data.append(self.PASSPHRASE)
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
seed_screens.SeedFinalizeScreen, seed_screens.SeedFinalizeScreen,
@@ -341,7 +338,7 @@ class SeedFinalizeView(View):
seed_num = self.controller.storage.finalize_pending_seed() seed_num = self.controller.storage.finalize_pending_seed()
return Destination(SeedOptionsView, view_args={"seed_num": seed_num}, clear_history=True) return Destination(SeedOptionsView, view_args={"seed_num": seed_num}, clear_history=True)
elif button_data[selected_menu_num] == passphrase_button: elif button_data[selected_menu_num] == self.PASSPHRASE:
return Destination(SeedAddPassphraseView) return Destination(SeedAddPassphraseView)
elif selected_menu_num == RET_CODE__BACK_BUTTON: elif selected_menu_num == RET_CODE__BACK_BUTTON:
@@ -377,8 +374,8 @@ class SeedAddPassphraseView(View):
class SeedAddPassphraseExitDialogView(View): class SeedAddPassphraseExitDialogView(View):
EDIT = _("Edit passphrase") EDIT = ButtonOption("Edit passphrase")
DISCARD = (_("Discard passphrase"), None, None, "red") DISCARD = ButtonOption("Discard passphrase", button_label_color="red")
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@@ -410,8 +407,8 @@ class SeedReviewPassphraseView(View):
""" """
Display the completed passphrase back to the user. Display the completed passphrase back to the user.
""" """
EDIT = _("Edit passphrase") EDIT = ButtonOption("Edit passphrase")
DONE = _("Done") DONE = ButtonOption("Done")
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@@ -450,8 +447,8 @@ class SeedReviewPassphraseView(View):
class SeedDiscardView(View): class SeedDiscardView(View):
KEEP = _("Keep Seed") KEEP = ButtonOption("Keep Seed")
DISCARD = (_("Discard"), None, None, "red") DISCARD = ButtonOption("Discard", button_label_color="red")
def __init__(self, seed_num: int = None): def __init__(self, seed_num: int = None):
super().__init__() super().__init__()
@@ -518,14 +515,14 @@ class SeedElectrumMnemonicStartView(View):
Views for actions on individual seeds: Views for actions on individual seeds:
****************************************************************************""" ****************************************************************************"""
class SeedOptionsView(View): class SeedOptionsView(View):
SCAN_PSBT = (_("Scan PSBT"), SeedSignerIconConstants.QRCODE) SCAN_PSBT = ButtonOption("Scan PSBT", SeedSignerIconConstants.QRCODE)
VERIFY_ADDRESS = _("Verify Addr") VERIFY_ADDRESS = ButtonOption("Verify Addr")
EXPORT_XPUB = _("Export Xpub") EXPORT_XPUB = ButtonOption("Export Xpub")
EXPLORER = _("Address Explorer") EXPLORER = ButtonOption("Address Explorer")
SIGN_MESSAGE = _("Sign Message") SIGN_MESSAGE = ButtonOption("Sign Message")
BACKUP = (_("Backup Seed"), None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT) BACKUP = ButtonOption("Backup Seed", right_icon_name=SeedSignerIconConstants.CHEVRON_RIGHT)
BIP85_CHILD_SEED = _("BIP-85 Child Seed") BIP85_CHILD_SEED = ButtonOption("BIP-85 Child Seed")
DISCARD = (_("Discard Seed"), None, None, "red") DISCARD = ButtonOption("Discard Seed", button_label_color="red")
def __init__(self, seed_num: int): def __init__(self, seed_num: int):
@@ -630,8 +627,8 @@ class SeedOptionsView(View):
class SeedBackupView(View): class SeedBackupView(View):
VIEW_WORDS = _("View Seed Words") VIEW_WORDS = ButtonOption("View Seed Words")
EXPORT_SEEDQR = _("Export as SeedQR") EXPORT_SEEDQR = ButtonOption("Export as SeedQR")
def __init__(self, seed_num): def __init__(self, seed_num):
super().__init__() super().__init__()
@@ -667,8 +664,8 @@ class SeedBackupView(View):
Export Xpub flow Export Xpub flow
****************************************************************************""" ****************************************************************************"""
class SeedExportXpubSigTypeView(View): class SeedExportXpubSigTypeView(View):
SINGLE_SIG = _("Single Sig") SINGLE_SIG = ButtonOption("Single Sig", return_data=SettingsConstants.SINGLE_SIG)
MULTISIG = _("Multisig") MULTISIG = ButtonOption("Multisig", return_data=SettingsConstants.MULTISIG)
def __init__(self, seed_num: int): def __init__(self, seed_num: int):
super().__init__() super().__init__()
@@ -680,7 +677,7 @@ class SeedExportXpubSigTypeView(View):
# Nothing to select; skip this screen # Nothing to select; skip this screen
return Destination(SeedExportXpubScriptTypeView, view_args={"seed_num": self.seed_num, "sig_type": self.settings.get_value(SettingsConstants.SETTING__SIG_TYPES)[0]}, skip_current_view=True) return Destination(SeedExportXpubScriptTypeView, view_args={"seed_num": self.seed_num, "sig_type": self.settings.get_value(SettingsConstants.SETTING__SIG_TYPES)[0]}, skip_current_view=True)
button_data=[self.SINGLE_SIG, self.MULTISIG] button_data = [self.SINGLE_SIG, self.MULTISIG]
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
ButtonListScreen, ButtonListScreen,
@@ -691,11 +688,7 @@ class SeedExportXpubSigTypeView(View):
if selected_menu_num == RET_CODE__BACK_BUTTON: if selected_menu_num == RET_CODE__BACK_BUTTON:
return Destination(BackStackView) return Destination(BackStackView)
if button_data[selected_menu_num] == self.SINGLE_SIG: return Destination(SeedExportXpubScriptTypeView, view_args={"seed_num": self.seed_num, "sig_type": button_data[selected_menu_num].return_data})
return Destination(SeedExportXpubScriptTypeView, view_args={"seed_num": self.seed_num, "sig_type": SettingsConstants.SINGLE_SIG})
elif button_data[selected_menu_num] == self.MULTISIG:
return Destination(SeedExportXpubScriptTypeView, view_args={"seed_num": self.seed_num, "sig_type": SettingsConstants.MULTISIG})
@@ -737,13 +730,13 @@ class SeedExportXpubScriptTypeView(View):
button_data = [] button_data = []
for script_type, display_name in SettingsConstants.ALL_SCRIPT_TYPES: for script_type, display_name in SettingsConstants.ALL_SCRIPT_TYPES:
if script_type in self.settings.get_value(SettingsConstants.SETTING__SCRIPT_TYPES): if script_type in self.settings.get_value(SettingsConstants.SETTING__SCRIPT_TYPES):
button_data.append((script_type, display_name)) button_data.append(ButtonOption(display_name, return_data=script_type))
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
ButtonListScreen, ButtonListScreen,
title=title, title=title,
is_button_text_centered=False, is_button_text_centered=False,
button_data=[x[1] for x in button_data], button_data=button_data,
is_bottom_list=True, is_bottom_list=True,
) )
@@ -754,7 +747,7 @@ class SeedExportXpubScriptTypeView(View):
return Destination(BackStackView) return Destination(BackStackView)
else: else:
args["script_type"] = button_data[selected_menu_num][0] args["script_type"] = button_data[selected_menu_num].return_data
if args["script_type"] == SettingsConstants.CUSTOM_DERIVATION: if args["script_type"] == SettingsConstants.CUSTOM_DERIVATION:
return Destination(SeedExportXpubCustomDerivationView, view_args=args) return Destination(SeedExportXpubCustomDerivationView, view_args=args)
@@ -826,7 +819,9 @@ class SeedExportXpubCoordinatorView(View):
args["coordinator"] = self.settings.get_value(SettingsConstants.SETTING__COORDINATORS)[0] args["coordinator"] = self.settings.get_value(SettingsConstants.SETTING__COORDINATORS)[0]
return Destination(SeedExportXpubWarningView, view_args=args, skip_current_view=True) return Destination(SeedExportXpubWarningView, view_args=args, skip_current_view=True)
button_data = self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS) button_data = []
for display_name, setting_option in zip(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS), self.settings.get_value(SettingsConstants.SETTING__COORDINATORS)):
button_data.append(ButtonOption(display_name, return_data=setting_option))
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
ButtonListScreen, ButtonListScreen,
@@ -838,9 +833,10 @@ class SeedExportXpubCoordinatorView(View):
if selected_menu_num == RET_CODE__BACK_BUTTON: if selected_menu_num == RET_CODE__BACK_BUTTON:
return Destination(BackStackView) return Destination(BackStackView)
coordinators_settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__COORDINATORS) # coordinators_settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__COORDINATORS)
selected_display_name = button_data[selected_menu_num] # selected_display_name = button_data[selected_menu_num]
args["coordinator"] = coordinators_settings_entry.get_selection_option_value_by_display_name(selected_display_name) # args["coordinator"] = coordinators_settings_entry.get_selection_option_value_by_display_name(selected_display_name)
args["coordinator"] = button_data[selected_menu_num].return_data
return Destination(SeedExportXpubWarningView, view_args=args) return Destination(SeedExportXpubWarningView, view_args=args)
@@ -1048,8 +1044,8 @@ class SeedWordsWarningView(View):
class SeedWordsView(View): class SeedWordsView(View):
NEXT = _("Next") NEXT = ButtonOption("Next")
DONE = _("Done") DONE = ButtonOption("Done")
def __init__(self, seed_num: int, bip85_data: dict = None, page_index: int = 0): def __init__(self, seed_num: int, bip85_data: dict = None, page_index: int = 0):
super().__init__() super().__init__()
@@ -1126,14 +1122,14 @@ class SeedBIP85ApplicationModeView(View):
* XPRV (BIP32) * XPRV (BIP32)
""" """
# TODO: Future enhancement to display WIF (HD-SEED) and XPRV (Bip32)? # TODO: Future enhancement to display WIF (HD-SEED) and XPRV (Bip32)?
WORDS_12 = _("12 Words") WORDS_12 = ButtonOption("12 Words")
WORDS_24 = _("24 Words") WORDS_24 = ButtonOption("24 Words")
def __init__(self, seed_num: int): def __init__(self, seed_num: int):
super().__init__() super().__init__()
self.seed_num = seed_num self.seed_num = seed_num
self.num_words = 0 self.num_words = 0
self.bip85_app_num = 39 # TODO: Support other Application numbers self.bip85_app_num = 39 # TODO: Support other Application numbers; TODO: Define this as a constant
def run(self): def run(self):
@@ -1159,8 +1155,8 @@ class SeedBIP85ApplicationModeView(View):
# View to retrieve the derived seed index
class SeedBIP85SelectChildIndexView(View): class SeedBIP85SelectChildIndexView(View):
# View to retrieve the derived seed index
def __init__(self, seed_num: int, num_words: int): def __init__(self, seed_num: int, num_words: int):
super().__init__() super().__init__()
self.seed_num = seed_num self.seed_num = seed_num
@@ -1168,7 +1164,7 @@ class SeedBIP85SelectChildIndexView(View):
def run(self): def run(self):
# Change this later to use the generic Screen input keyboard # TODO: Change this later to use the generic Screen input keyboard
ret = seed_screens.SeedBIP85SelectChildIndexScreen().display() ret = seed_screens.SeedBIP85SelectChildIndexScreen().display()
if ret == RET_CODE__BACK_BUTTON: if ret == RET_CODE__BACK_BUTTON:
@@ -1206,7 +1202,7 @@ class SeedBIP85InvalidChildIndexView(View):
show_back_button=False, show_back_button=False,
status_headline=_("Invalid Child Index"), status_headline=_("Invalid Child Index"),
text=_("BIP-85 Child Index must be between 0 and 2^31-1."), text=_("BIP-85 Child Index must be between 0 and 2^31-1."),
button_data=[_("Try Again")] button_data=[ButtonOption("Try Again")]
).display() ).display()
return Destination( return Destination(
@@ -1224,8 +1220,8 @@ class SeedBIP85InvalidChildIndexView(View):
Seed Words Backup Test Seed Words Backup Test
****************************************************************************""" ****************************************************************************"""
class SeedWordsBackupTestPromptView(View): class SeedWordsBackupTestPromptView(View):
VERIFY = _("Verify") VERIFY = ButtonOption("Verify")
SKIP = _("Skip") SKIP = ButtonOption("Skip")
def __init__(self, seed_num: int, bip85_data: dict = None): def __init__(self, seed_num: int, bip85_data: dict = None):
super().__init__() super().__init__()
@@ -1283,10 +1279,10 @@ class SeedWordsBackupTestView(View):
while self.cur_index in self.confirmed_list: while self.cur_index in self.confirmed_list:
self.cur_index = int(random.random() * len(self.mnemonic_list)) self.cur_index = int(random.random() * len(self.mnemonic_list))
real_word = self.mnemonic_list[self.cur_index] real_word = ButtonOption(self.mnemonic_list[self.cur_index])
fake_word1 = bip39.WORDLIST[int(random.random() * 2047)] fake_word1 = ButtonOption(bip39.WORDLIST[int(random.random() * 2047)])
fake_word2 = bip39.WORDLIST[int(random.random() * 2047)] fake_word2 = ButtonOption(bip39.WORDLIST[int(random.random() * 2047)])
fake_word3 = bip39.WORDLIST[int(random.random() * 2047)] fake_word3 = ButtonOption(bip39.WORDLIST[int(random.random() * 2047)])
button_data = [real_word, fake_word1, fake_word2, fake_word3] button_data = [real_word, fake_word1, fake_word2, fake_word3]
random.shuffle(button_data) random.shuffle(button_data)
@@ -1332,8 +1328,8 @@ class SeedWordsBackupTestView(View):
class SeedWordsBackupTestMistakeView(View): class SeedWordsBackupTestMistakeView(View):
REVIEW = _("Review Seed Words") REVIEW = ButtonOption("Review Seed Words")
RETRY = _("Try Again") RETRY = ButtonOption("Try Again")
def __init__(self, seed_num: int, bip85_data: dict = None, cur_index: int = None, wrong_word: str = None, confirmed_list: list[bool] = None): def __init__(self, seed_num: int, bip85_data: dict = None, cur_index: int = None, wrong_word: str = None, confirmed_list: list[bool] = None):
super().__init__() super().__init__()
@@ -1392,7 +1388,7 @@ class SeedWordsBackupTestSuccessView(View):
show_back_button=False, show_back_button=False,
status_headline=_("Success!"), status_headline=_("Success!"),
text=_("All mnemonic backup words were successfully verified!"), text=_("All mnemonic backup words were successfully verified!"),
button_data=[_("OK")] button_data=[ButtonOption("OK")]
).display() ).display()
if self.seed_num is not None: if self.seed_num is not None:
@@ -1414,15 +1410,11 @@ class SeedTranscribeSeedQRFormatView(View):
def run(self): def run(self):
seed = self.controller.get_seed(self.seed_num) seed = self.controller.get_seed(self.seed_num)
if len(seed.mnemonic_list) == 12: if len(seed.mnemonic_list) == 12:
STANDARD = _("Standard: 25x25") STANDARD = ButtonOption("Standard: 25x25", return_data=25)
COMPACT = _("Compact: 21x21") COMPACT = ButtonOption("Compact: 21x21", return_data=21)
num_modules_standard = 25
num_modules_compact = 21
else: else:
STANDARD = _("Standard: 29x29") STANDARD = ButtonOption("Standard: 29x29", return_data=29)
COMPACT = _("Compact: 25x25") COMPACT = ButtonOption("Compact: 25x25", return_data=25)
num_modules_standard = 29
num_modules_compact = 25
if self.settings.get_value(SettingsConstants.SETTING__COMPACT_SEEDQR) != SettingsConstants.OPTION__ENABLED: if self.settings.get_value(SettingsConstants.SETTING__COMPACT_SEEDQR) != SettingsConstants.OPTION__ENABLED:
# Only configured for standard SeedQR # Only configured for standard SeedQR
@@ -1431,7 +1423,7 @@ class SeedTranscribeSeedQRFormatView(View):
view_args={ view_args={
"seed_num": self.seed_num, "seed_num": self.seed_num,
"seedqr_format": QRType.SEED__SEEDQR, "seedqr_format": QRType.SEED__SEEDQR,
"num_modules": num_modules_standard, "num_modules": STANDARD.return_data,
}, },
skip_current_view=True, skip_current_view=True,
) )
@@ -1450,10 +1442,10 @@ class SeedTranscribeSeedQRFormatView(View):
if button_data[selected_menu_num] == STANDARD: if button_data[selected_menu_num] == STANDARD:
seedqr_format = QRType.SEED__SEEDQR seedqr_format = QRType.SEED__SEEDQR
num_modules = num_modules_standard
else: else:
seedqr_format = QRType.SEED__COMPACTSEEDQR seedqr_format = QRType.SEED__COMPACTSEEDQR
num_modules = num_modules_compact
num_modules = button_data[selected_menu_num].return_data
return Destination( return Destination(
SeedTranscribeSeedQRWarningView, SeedTranscribeSeedQRWarningView,
@@ -1580,8 +1572,8 @@ class SeedTranscribeSeedQRZoomedInView(View):
class SeedTranscribeSeedQRConfirmQRPromptView(View): class SeedTranscribeSeedQRConfirmQRPromptView(View):
SCAN = (_("Confirm SeedQR"), SeedSignerIconConstants.QRCODE) SCAN = ButtonOption("Confirm SeedQR", SeedSignerIconConstants.QRCODE)
DONE = _("Done") DONE = ButtonOption("Done")
def __init__(self, seed_num: int): def __init__(self, seed_num: int):
super().__init__() super().__init__()
@@ -1726,8 +1718,8 @@ class AddressVerificationStartView(View):
class AddressVerificationSigTypeView(View): class AddressVerificationSigTypeView(View):
SINGLE_SIG = _("Single Sig") SINGLE_SIG = ButtonOption("Single Sig")
MULTISIG = _("Multisig") MULTISIG = ButtonOption("Multisig")
def run(self): def run(self):
from seedsigner.helpers import embit_utils from seedsigner.helpers import embit_utils
@@ -1781,8 +1773,8 @@ class SeedAddressVerificationView(View):
multisig. multisig.
""" """
# TRANSLATOR_NOTE: Option when scanning for a matching address; skips ten addresses ahead # TRANSLATOR_NOTE: Option when scanning for a matching address; skips ten addresses ahead
SKIP_10 = _("Skip 10") SKIP_10 = ButtonOption("Skip 10")
CANCEL = _("Cancel") CANCEL = ButtonOption("Cancel")
def __init__(self, seed_num: int = None): def __init__(self, seed_num: int = None):
super().__init__() super().__init__()
@@ -2000,8 +1992,8 @@ class AddressVerificationSuccessView(View):
class LoadMultisigWalletDescriptorView(View): class LoadMultisigWalletDescriptorView(View):
SCAN = (_("Scan Descriptor"), SeedSignerIconConstants.QRCODE) SCAN = ButtonOption("Scan Descriptor", SeedSignerIconConstants.QRCODE)
CANCEL = _("Cancel") CANCEL = ButtonOption("Cancel")
def run(self): def run(self):
button_data = [self.SCAN, self.CANCEL] button_data = [self.SCAN, self.CANCEL]
@@ -2025,10 +2017,10 @@ class LoadMultisigWalletDescriptorView(View):
class MultisigWalletDescriptorView(View): class MultisigWalletDescriptorView(View):
RETURN = _("Return to PSBT") RETURN = ButtonOption("Return to PSBT")
VERIFY_ADDR = _("Verify Addr") VERIFY_ADDR = ButtonOption("Verify Addr")
ADDRESS_EXPLORER = _("Address Explorer") ADDRESS_EXPLORER = ButtonOption("Address Explorer")
OK = _("OK") OK = ButtonOption("OK")
def run(self): def run(self):
descriptor = self.controller.multisig_wallet_descriptor descriptor = self.controller.multisig_wallet_descriptor
@@ -2047,8 +2039,8 @@ class MultisigWalletDescriptorView(View):
if self.controller.resume_main_flow == Controller.FLOW__PSBT: if self.controller.resume_main_flow == Controller.FLOW__PSBT:
button_data = [self.RETURN] button_data = [self.RETURN]
elif self.controller.resume_main_flow == Controller.FLOW__VERIFY_MULTISIG_ADDR and self.controller.unverified_address: elif self.controller.resume_main_flow == Controller.FLOW__VERIFY_MULTISIG_ADDR and self.controller.unverified_address:
verify_addr_display = f"""{self.VERIFY_ADDR} {self.controller.unverified_address["address"][:7]}""" verify_addr_display = f"""{_(self.VERIFY_ADDR.button_label)} {self.controller.unverified_address["address"][:7]}"""
button_data = [verify_addr_display] button_data = [ButtonOption(verify_addr_display)]
elif self.controller.resume_main_flow == Controller.FLOW__ADDRESS_EXPLORER: elif self.controller.resume_main_flow == Controller.FLOW__ADDRESS_EXPLORER:
button_data = [self.ADDRESS_EXPLORER] button_data = [self.ADDRESS_EXPLORER]
@@ -2069,7 +2061,7 @@ class MultisigWalletDescriptorView(View):
self.controller.resume_main_flow = None self.controller.resume_main_flow = None
return Destination(PSBTChangeDetailsView, view_args=dict(change_address_num=0)) return Destination(PSBTChangeDetailsView, view_args=dict(change_address_num=0))
elif button_data[selected_menu_num].startswith(self.VERIFY_ADDR): elif button_data[selected_menu_num].button_label.startswith(_(self.VERIFY_ADDR.button_label)):
self.controller.resume_main_flow = None self.controller.resume_main_flow = None
return Destination(SeedAddressVerificationView) return Destination(SeedAddressVerificationView)
@@ -2111,12 +2103,7 @@ class SeedSignMessageStartView(View):
# Note: addr_format["network"] can be MAINNET or [TESTNET, REGTEST] # Note: addr_format["network"] can be MAINNET or [TESTNET, REGTEST]
if self.settings.get_value(SettingsConstants.SETTING__NETWORK) not in addr_format["network"]: if self.settings.get_value(SettingsConstants.SETTING__NETWORK) not in addr_format["network"]:
from seedsigner.views.view import NetworkMismatchErrorView from seedsigner.views.view import NetworkMismatchErrorView
# TRANSLATOR_NOTE: Inserts mainnet/testnet/regtest and derivation path self.set_redirect(Destination(NetworkMismatchErrorView, view_args=dict(derivation_path=self.derivation_path)))
text = _("Current network setting ({}) doesn't match {}").format(
self.settings.get_value_display_name(SettingsConstants.SETTING__NETWORK),
self.derivation_path,
)
self.set_redirect(Destination(NetworkMismatchErrorView, view_args=dict(text=text)))
# cleanup. Note: We could leave this in place so the user can resume the # cleanup. Note: We could leave this in place so the user can resume the
# flow, but for now we avoid complications and keep things simple. # flow, but for now we avoid complications and keep things simple.
@@ -2203,11 +2190,7 @@ class SeedSignMessageConfirmAddressView(View):
addr_format["network"] = self.settings.get_value(SettingsConstants.SETTING__NETWORK) addr_format["network"] = self.settings.get_value(SettingsConstants.SETTING__NETWORK)
else: else:
from seedsigner.views.view import NetworkMismatchErrorView from seedsigner.views.view import NetworkMismatchErrorView
text = _("Current network setting ({}) doesn't match {}").format( self.set_redirect(Destination(NetworkMismatchErrorView, view_args=dict(derivation_path=self.derivation_path)))
self.settings.get_value_display_name(SettingsConstants.SETTING__NETWORK),
self.derivation_path,
)
self.set_redirect(Destination(NetworkMismatchErrorView, view_args=dict(text=text)))
# cleanup. Note: We could leave this in place so the user can resume the # cleanup. Note: We could leave this in place so the user can resume the
# flow, but for now we avoid complications and keep things simple. # flow, but for now we avoid complications and keep things simple.
+6 -6
View File
@@ -3,6 +3,7 @@ from gettext import gettext as _
from seedsigner.gui.components import SeedSignerIconConstants from seedsigner.gui.components import SeedSignerIconConstants
from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, settings_screens) from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, settings_screens)
from seedsigner.gui.screens.screen import ButtonOption
from seedsigner.models.settings import Settings, SettingsConstants, SettingsDefinition from seedsigner.models.settings import Settings, SettingsConstants, SettingsDefinition
from .view import View, Destination, MainMenuView from .view import View, Destination, MainMenuView
@@ -12,8 +13,8 @@ logger = logging.getLogger(__name__)
class SettingsMenuView(View): class SettingsMenuView(View):
IO_TEST = _("I/O test") IO_TEST = ButtonOption("I/O test")
DONATE = _("Donate") DONATE = ButtonOption("Donate")
def __init__(self, visibility: str = SettingsConstants.VISIBILITY__GENERAL, selected_attr: str = None, initial_scroll: int = 0): def __init__(self, visibility: str = SettingsConstants.VISIBILITY__GENERAL, selected_attr: str = None, initial_scroll: int = 0):
super().__init__() super().__init__()
@@ -28,7 +29,7 @@ class SettingsMenuView(View):
settings_entries = SettingsDefinition.get_settings_entries( settings_entries = SettingsDefinition.get_settings_entries(
visibility=self.visibility visibility=self.visibility
) )
button_data=[e.display_name for e in settings_entries] button_data=[ButtonOption(e.display_name) for e in settings_entries]
selected_button = 0 selected_button = 0
if self.selected_attr: if self.selected_attr:
@@ -41,7 +42,7 @@ class SettingsMenuView(View):
title = _("Settings") title = _("Settings")
# Set up the next nested level of menuing # Set up the next nested level of menuing
button_data.append((_("Advanced"), None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT)) button_data.append(ButtonOption("Advanced", right_icon_name=SeedSignerIconConstants.CHEVRON_RIGHT))
next_destination = Destination(SettingsMenuView, view_args={"visibility": SettingsConstants.VISIBILITY__ADVANCED}) next_destination = Destination(SettingsMenuView, view_args={"visibility": SettingsConstants.VISIBILITY__ADVANCED})
button_data.append(self.IO_TEST) button_data.append(self.IO_TEST)
@@ -114,7 +115,7 @@ class SettingsEntryUpdateSelectionView(View):
value, display_name = value value, display_name = value
else: else:
display_name = value display_name = value
button_data.append(display_name) button_data.append(ButtonOption(display_name))
if (type(initial_value) == list and value in initial_value) or value == initial_value: if (type(initial_value) == list and value in initial_value) or value == initial_value:
checked_buttons.append(i) checked_buttons.append(i)
@@ -211,7 +212,6 @@ class SettingsIngestSettingsQRView(View):
SettingsQRConfirmationScreen, SettingsQRConfirmationScreen,
title=_("Settings QR"), title=_("Settings QR"),
config_name=self.config_name, config_name=self.config_name,
button_data=[_("Home")],
status_message=self.status_message, status_message=self.status_message,
) )
+51 -56
View File
@@ -7,6 +7,7 @@ from gettext import gettext as _
from seedsigner.gui.components import FontAwesomeIconConstants, GUIConstants, SeedSignerIconConstants from seedsigner.gui.components import FontAwesomeIconConstants, GUIConstants, SeedSignerIconConstants
from seedsigner.gui.screens import RET_CODE__BACK_BUTTON, ButtonListScreen from seedsigner.gui.screens import RET_CODE__BACK_BUTTON, ButtonListScreen
from seedsigner.gui.screens.screen import ButtonOption
from seedsigner.helpers import mnemonic_generation from seedsigner.helpers import mnemonic_generation
from seedsigner.models.seed import Seed from seedsigner.models.seed import Seed
from seedsigner.models.settings_definition import SettingsConstants from seedsigner.models.settings_definition import SettingsConstants
@@ -19,11 +20,11 @@ logger = logging.getLogger(__name__)
class ToolsMenuView(View): class ToolsMenuView(View):
IMAGE = (_("New seed"), FontAwesomeIconConstants.CAMERA) IMAGE = ButtonOption("New seed", FontAwesomeIconConstants.CAMERA)
DICE = (_("New seed"), FontAwesomeIconConstants.DICE) DICE = ButtonOption("New seed", FontAwesomeIconConstants.DICE)
KEYBOARD = (_("Calc 12th/24th word"), FontAwesomeIconConstants.KEYBOARD) KEYBOARD = ButtonOption("Calc 12th/24th word", FontAwesomeIconConstants.KEYBOARD)
ADDRESS_EXPLORER = _("Address Explorer") ADDRESS_EXPLORER = ButtonOption("Address Explorer")
VERIFY_ADDRESS = _("Verify Address") VERIFY_ADDRESS = ButtonOption("Verify Address")
def run(self): def run(self):
button_data = [self.IMAGE, self.DICE, self.KEYBOARD, self.ADDRESS_EXPLORER, self.VERIFY_ADDRESS] button_data = [self.IMAGE, self.DICE, self.KEYBOARD, self.ADDRESS_EXPLORER, self.VERIFY_ADDRESS]
@@ -113,8 +114,8 @@ class ToolsImageEntropyFinalImageView(View):
class ToolsImageEntropyMnemonicLengthView(View): class ToolsImageEntropyMnemonicLengthView(View):
TWELVE_WORDS = _("12 words") TWELVE_WORDS = ButtonOption("12 words", return_data=12)
TWENTYFOUR_WORDS = _("24 words") TWENTYFOUR_WORDS = ButtonOption("24 words", return_data=24)
def run(self): def run(self):
button_data = [self.TWELVE_WORDS, self.TWENTYFOUR_WORDS] button_data = [self.TWELVE_WORDS, self.TWENTYFOUR_WORDS]
@@ -127,10 +128,7 @@ class ToolsImageEntropyMnemonicLengthView(View):
if selected_menu_num == RET_CODE__BACK_BUTTON: if selected_menu_num == RET_CODE__BACK_BUTTON:
return Destination(BackStackView) return Destination(BackStackView)
if button_data[selected_menu_num] == self.TWELVE_WORDS: mnemonic_length = button_data[selected_menu_num].return_data
mnemonic_length = 12
else:
mnemonic_length = 24
preview_images = self.controller.image_entropy_preview_frames preview_images = self.controller.image_entropy_preview_frames
seed_entropy_image = self.controller.image_entropy_final_image seed_entropy_image = self.controller.image_entropy_final_image
@@ -186,15 +184,19 @@ class ToolsImageEntropyMnemonicLengthView(View):
Dice rolls Views Dice rolls Views
****************************************************************************""" ****************************************************************************"""
class ToolsDiceEntropyMnemonicLengthView(View): class ToolsDiceEntropyMnemonicLengthView(View):
# TRANSLATOR_NOTE: Inserts the number of dice rolls needed for a 12-word mnemonic
TWELVE = _("12 words ({} rolls)").format(mnemonic_generation.DICE__NUM_ROLLS__12WORD)
# TRANSLATOR_NOTE: Inserts the number of dice rolls needed for a 24-word mnemonic
TWENTY_FOUR = _("24 words ({} rolls)").format(mnemonic_generation.DICE__NUM_ROLLS__24WORD)
def run(self): def run(self):
button_data = [self.TWELVE, self.TWENTY_FOUR] # Since we're dynamically building the ButtonOption button_labels here, it's too
# awkward to use the usual class-level attr approach.
# TRANSLATOR_NOTE: Inserts the number of dice rolls needed for a 12-word mnemonic
twelve = _("12 words ({} rolls)").format(mnemonic_generation.DICE__NUM_ROLLS__12WORD)
TWELVE = ButtonOption(twelve, return_data=mnemonic_generation.DICE__NUM_ROLLS__12WORD)
# TRANSLATOR_NOTE: Inserts the number of dice rolls needed for a 24-word mnemonic
twenty_four = _("24 words ({} rolls)").format(mnemonic_generation.DICE__NUM_ROLLS__24WORD)
TWENTY_FOUR = ButtonOption(twenty_four, return_data=mnemonic_generation.DICE__NUM_ROLLS__24WORD)
button_data = [TWELVE, TWENTY_FOUR]
selected_menu_num = ButtonListScreen( selected_menu_num = ButtonListScreen(
title=_("Mnemonic Length"), title=_("Mnemonic Length"),
is_bottom_list=True, is_bottom_list=True,
@@ -205,10 +207,10 @@ class ToolsDiceEntropyMnemonicLengthView(View):
if selected_menu_num == RET_CODE__BACK_BUTTON: if selected_menu_num == RET_CODE__BACK_BUTTON:
return Destination(BackStackView) return Destination(BackStackView)
elif button_data[selected_menu_num] == self.TWELVE: elif button_data[selected_menu_num] == TWELVE:
return Destination(ToolsDiceEntropyEntryView, view_args=dict(total_rolls=mnemonic_generation.DICE__NUM_ROLLS__12WORD)) return Destination(ToolsDiceEntropyEntryView, view_args=dict(total_rolls=mnemonic_generation.DICE__NUM_ROLLS__12WORD))
elif button_data[selected_menu_num] == self.TWENTY_FOUR: elif button_data[selected_menu_num] == TWENTY_FOUR:
return Destination(ToolsDiceEntropyEntryView, view_args=dict(total_rolls=mnemonic_generation.DICE__NUM_ROLLS__24WORD)) return Destination(ToolsDiceEntropyEntryView, view_args=dict(total_rolls=mnemonic_generation.DICE__NUM_ROLLS__24WORD))
@@ -243,8 +245,8 @@ class ToolsDiceEntropyEntryView(View):
Calc final word Views Calc final word Views
****************************************************************************""" ****************************************************************************"""
class ToolsCalcFinalWordNumWordsView(View): class ToolsCalcFinalWordNumWordsView(View):
TWELVE = _("12 words") TWELVE = ButtonOption("12 words", return_data=12)
TWENTY_FOUR = _("24 words") TWENTY_FOUR = ButtonOption("24 words", return_data=24)
def run(self): def run(self):
button_data = [self.TWELVE, self.TWENTY_FOUR] button_data = [self.TWELVE, self.TWENTY_FOUR]
@@ -260,29 +262,21 @@ class ToolsCalcFinalWordNumWordsView(View):
if selected_menu_num == RET_CODE__BACK_BUTTON: if selected_menu_num == RET_CODE__BACK_BUTTON:
return Destination(BackStackView) return Destination(BackStackView)
elif button_data[selected_menu_num] == self.TWELVE: self.controller.storage.init_pending_mnemonic(button_data[selected_menu_num].return_data)
self.controller.storage.init_pending_mnemonic(12)
# return Destination(SeedMnemonicEntryView, view_args=dict(is_calc_final_word=True)) return Destination(SeedMnemonicEntryView, view_args=dict(is_calc_final_word=True))
return Destination(SeedMnemonicEntryView, view_args=dict(is_calc_final_word=True))
elif button_data[selected_menu_num] == self.TWENTY_FOUR:
self.controller.storage.init_pending_mnemonic(24)
# return Destination(SeedMnemonicEntryView, view_args=dict(is_calc_final_word=True))
return Destination(SeedMnemonicEntryView, view_args=dict(is_calc_final_word=True))
class ToolsCalcFinalWordFinalizePromptView(View): class ToolsCalcFinalWordFinalizePromptView(View):
# TRANSLATOR_NOTE: Label to gather entropy through coin tosses # TRANSLATOR_NOTE: Label to gather entropy through coin tosses
COIN_FLIPS = _("Coin flip entropy") COIN_FLIPS = ButtonOption("Coin flip entropy")
# TRANSLATOR_NOTE: Label to gather entropy through user specified BIP-39 word # TRANSLATOR_NOTE: Label to gather entropy through user specified BIP-39 word
SELECT_WORD = _("Word selection entropy") SELECT_WORD = ButtonOption("Word selection entropy")
# TRANSLATOR_NOTE: Label to allow user to default entropy as all-zeros # TRANSLATOR_NOTE: Label to allow user to default entropy as all-zeros
ZEROS = _("Finalize with zeros") ZEROS = ButtonOption("Finalize with zeros")
def run(self): def run(self):
from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordFinalizePromptScreen from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordFinalizePromptScreen
@@ -343,7 +337,7 @@ class ToolsCalcFinalWordCoinFlipsView(View):
class ToolsCalcFinalWordShowFinalWordView(View): class ToolsCalcFinalWordShowFinalWordView(View):
NEXT = _("Next") NEXT = ButtonOption("Next")
def __init__(self, coin_flips: str = None): def __init__(self, coin_flips: str = None):
super().__init__() super().__init__()
@@ -399,10 +393,13 @@ class ToolsCalcFinalWordShowFinalWordView(View):
def run(self): def run(self):
from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordScreen from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordScreen
button_data = [self.NEXT] button_data = [self.NEXT]
# TRANSLATOR_NOTE: label to calculate the last word of a BIP-39 mnemonic seed phrase
title = _("Final Word Calc")
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
ToolsCalcFinalWordScreen, ToolsCalcFinalWordScreen,
# TRANSLATOR_NOTE: label to calculate the last word of a BIP-39 mnemonic seed phrase title=title,
title=_("Final Word Calc"),
button_data=button_data, button_data=button_data,
selected_final_word=self.selected_final_word, selected_final_word=self.selected_final_word,
selected_final_bits=self.selected_final_bits, selected_final_bits=self.selected_final_bits,
@@ -419,8 +416,8 @@ class ToolsCalcFinalWordShowFinalWordView(View):
class ToolsCalcFinalWordDoneView(View): class ToolsCalcFinalWordDoneView(View):
LOAD = _("Load seed") LOAD = ButtonOption("Load seed")
DISCARD = (_("Discard"), None, None, "red") DISCARD = ButtonOption("Discard", button_label_color="red")
def run(self): def run(self):
from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordDoneScreen from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordDoneScreen
@@ -454,11 +451,11 @@ class ToolsCalcFinalWordDoneView(View):
Address Explorer Views Address Explorer Views
****************************************************************************""" ****************************************************************************"""
class ToolsAddressExplorerSelectSourceView(View): class ToolsAddressExplorerSelectSourceView(View):
SCAN_SEED = (_("Scan a seed"), SeedSignerIconConstants.QRCODE) SCAN_SEED = ButtonOption("Scan a seed", SeedSignerIconConstants.QRCODE)
SCAN_DESCRIPTOR = (_("Scan wallet descriptor"), SeedSignerIconConstants.QRCODE) SCAN_DESCRIPTOR = ButtonOption("Scan wallet descriptor", SeedSignerIconConstants.QRCODE)
TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD, return_data=12)
TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD, return_data=24)
TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD)
def run(self): def run(self):
from seedsigner.controller import Controller from seedsigner.controller import Controller
@@ -467,11 +464,11 @@ class ToolsAddressExplorerSelectSourceView(View):
button_data = [] button_data = []
for seed in seeds: for seed in seeds:
button_str = seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK)) button_str = seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK))
button_data.append((button_str, SeedSignerIconConstants.FINGERPRINT)) button_data.append(ButtonOption(button_str, SeedSignerIconConstants.FINGERPRINT))
button_data = button_data + [self.SCAN_SEED, self.SCAN_DESCRIPTOR, self.TYPE_12WORD, self.TYPE_24WORD] button_data = button_data + [self.SCAN_SEED, self.SCAN_DESCRIPTOR, self.TYPE_12WORD, self.TYPE_24WORD]
if self.settings.get_value(SettingsConstants.SETTING__ELECTRUM_SEEDS) == SettingsConstants.OPTION__ENABLED: if self.settings.get_value(SettingsConstants.SETTING__ELECTRUM_SEEDS) == SettingsConstants.OPTION__ENABLED:
button_data.append(self.TYPE_ELECTRUM) button_data.append(self.TYPE_ELECTRUM)
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
ButtonListScreen, ButtonListScreen,
title=_("Address Explorer"), title=_("Address Explorer"),
@@ -508,10 +505,7 @@ class ToolsAddressExplorerSelectSourceView(View):
elif button_data[selected_menu_num] in [self.TYPE_12WORD, self.TYPE_24WORD]: elif button_data[selected_menu_num] in [self.TYPE_12WORD, self.TYPE_24WORD]:
from seedsigner.views.seed_views import SeedMnemonicEntryView from seedsigner.views.seed_views import SeedMnemonicEntryView
if button_data[selected_menu_num] == self.TYPE_12WORD: self.controller.storage.init_pending_mnemonic(num_words=button_data[selected_menu_num].return_data)
self.controller.storage.init_pending_mnemonic(num_words=12)
else:
self.controller.storage.init_pending_mnemonic(num_words=24)
return Destination(SeedMnemonicEntryView) return Destination(SeedMnemonicEntryView)
elif button_data[selected_menu_num] == self.TYPE_ELECTRUM: elif button_data[selected_menu_num] == self.TYPE_ELECTRUM:
@@ -522,10 +516,10 @@ class ToolsAddressExplorerSelectSourceView(View):
class ToolsAddressExplorerAddressTypeView(View): class ToolsAddressExplorerAddressTypeView(View):
# TRANSLATOR_NOTE: label for addresses where others send us incoming payments # TRANSLATOR_NOTE: label for addresses where others send us incoming payments
RECEIVE = _("Receive Addresses") RECEIVE = ButtonOption("Receive Addresses")
# TRANSLATOR_NOTE: label for addresses that collect the change from our own outgoing payments # TRANSLATOR_NOTE: label for addresses that collect the change from our own outgoing payments
CHANGE = _("Change Addresses") CHANGE = ButtonOption("Change Addresses")
def __init__(self, seed_num: int = None, script_type: str = None, custom_derivation: str = None): def __init__(self, seed_num: int = None, script_type: str = None, custom_derivation: str = None):
@@ -689,10 +683,11 @@ class ToolsAddressExplorerAddressListView(View):
end_digits = -5 end_digits = -5
else: else:
end_digits = -4 end_digits = -4
button_data.append(f"{cur_index}:{address[:8]}...{address[end_digits:]}") button_data.append(ButtonOption(f"{cur_index}:{address[:8]}...{address[end_digits:]}"))
# TRANSLATOR_NOTE: Insert the number of addrs displayed per screen (e.g. "Next 10") # TRANSLATOR_NOTE: Insert the number of addrs displayed per screen (e.g. "Next 10")
button_data.append((_("Next {}").format(addrs_per_screen), None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT)) button_label = _("Next {}").format(addrs_per_screen)
button_data.append(ButtonOption(button_label, right_icon_name=SeedSignerIconConstants.CHEVRON_RIGHT))
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
ButtonListScreen, ButtonListScreen,
+30 -63
View File
@@ -1,10 +1,11 @@
from dataclasses import dataclass, field from dataclasses import dataclass
from gettext import gettext as _ from gettext import gettext as _
from typing import Type from typing import Type
from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants from seedsigner.helpers.l10n import mark_for_translation as _mft
from seedsigner.gui.components import SeedSignerIconConstants
from seedsigner.gui.screens import RET_CODE__POWER_BUTTON, RET_CODE__BACK_BUTTON from seedsigner.gui.screens import RET_CODE__POWER_BUTTON, RET_CODE__BACK_BUTTON
from seedsigner.gui.screens.screen import BaseScreen, DireWarningScreen, LargeButtonScreen, PowerOffScreen, PowerOffNotRequiredScreen, ResetScreen, WarningScreen from seedsigner.gui.screens.screen import BaseScreen, ButtonOption, DireWarningScreen, LargeButtonScreen, PowerOffScreen, PowerOffNotRequiredScreen, ResetScreen, WarningScreen
from seedsigner.models.settings import Settings, SettingsConstants from seedsigner.models.settings import Settings, SettingsConstants
from seedsigner.models.settings_definition import SettingsDefinition from seedsigner.models.settings_definition import SettingsDefinition
from seedsigner.models.threads import BaseThread from seedsigner.models.threads import BaseThread
@@ -18,6 +19,7 @@ class BackStackView:
pass pass
""" """
Views contain the biz logic to handle discrete tasks, exactly analogous to a Flask Views contain the biz logic to handle discrete tasks, exactly analogous to a Flask
request/response function or a Django View. Each page/screen displayed to the user request/response function or a Django View. Each page/screen displayed to the user
@@ -182,14 +184,13 @@ class Destination:
# #
######################################################################################### #########################################################################################
class MainMenuView(View): class MainMenuView(View):
SCAN = (_("Scan"), SeedSignerIconConstants.SCAN) SCAN = ButtonOption("Scan", SeedSignerIconConstants.SCAN)
SEEDS = (_("Seeds"), SeedSignerIconConstants.SEEDS) SEEDS = ButtonOption("Seeds", SeedSignerIconConstants.SEEDS)
TOOLS = (_("Tools"), SeedSignerIconConstants.TOOLS) TOOLS = ButtonOption("Tools", SeedSignerIconConstants.TOOLS)
SETTINGS = (_("Settings"), SeedSignerIconConstants.SETTINGS) SETTINGS = ButtonOption("Settings", SeedSignerIconConstants.SETTINGS)
def run(self): def run(self):
from seedsigner.gui.screens.screen import MainMenuScreen from seedsigner.gui.screens.screen import MainMenuScreen
button_data = [self.SCAN, self.SEEDS, self.TOOLS, self.SETTINGS] button_data = [self.SCAN, self.SEEDS, self.TOOLS, self.SETTINGS]
selected_menu_num = self.run_screen( selected_menu_num = self.run_screen(
MainMenuScreen, MainMenuScreen,
@@ -219,8 +220,8 @@ class MainMenuView(View):
class PowerOptionsView(View): class PowerOptionsView(View):
RESET = (_("Restart"), SeedSignerIconConstants.RESTART) RESET = ButtonOption("Restart", SeedSignerIconConstants.RESTART)
POWER_OFF = (_("Power Off"), SeedSignerIconConstants.POWER) POWER_OFF = ButtonOption("Power Off", SeedSignerIconConstants.POWER)
def run(self): def run(self):
button_data = [self.RESET, self.POWER_OFF] button_data = [self.RESET, self.POWER_OFF]
@@ -293,12 +294,7 @@ class NotYetImplementedView(View):
""" """
Temporary View to use during dev. Temporary View to use during dev.
""" """
text: str = None text: str = _mft("This is still on our to-do list!")
def __post_init__(self):
if not self.text:
self.text = _("This is still on our to-do list!")
return super().__post_init__()
def run(self): def run(self):
@@ -307,7 +303,7 @@ class NotYetImplementedView(View):
title=_("Work In Progress"), title=_("Work In Progress"),
status_headline=_("Not Yet Implemented"), status_headline=_("Not Yet Implemented"),
text=self.text, text=self.text,
button_data=[_("Back to Main Menu")], button_data=[ButtonOption("Back to Main Menu")],
) )
return Destination(MainMenuView) return Destination(MainMenuView)
@@ -316,13 +312,12 @@ class NotYetImplementedView(View):
@dataclass @dataclass
class ErrorView(View): class ErrorView(View):
title: str = _("Error") title: str = _mft("Error")
show_back_button: bool = True show_back_button: bool = True
status_headline: str = None status_headline: str = None
text: str = None text: str = None
button_text: str = None button_text: str = None
next_destination: Destination = field(default_factory=lambda: Destination(MainMenuView, clear_history=True)) next_destination: Destination = None
def run(self): def run(self):
self.run_screen( self.run_screen(
@@ -330,33 +325,30 @@ class ErrorView(View):
title=self.title, title=self.title,
status_headline=self.status_headline, status_headline=self.status_headline,
text=self.text, text=self.text,
button_data=[self.button_text], button_data=[ButtonOption(self.button_text)],
show_back_button=self.show_back_button, show_back_button=self.show_back_button,
) )
return self.next_destination if self.next_destination else Destination(MainMenuView, clear_history=True)
return self.next_destination
@dataclass @dataclass
class NetworkMismatchErrorView(ErrorView): class NetworkMismatchErrorView(ErrorView):
title: str = _("Network Mismatch") derivation_path: str = None
show_back_button: bool = False
button_text: str = _("Change Setting")
next_destination: Destination = None
def __post_init__(self): def __post_init__(self):
from seedsigner.views.settings_views import SettingsEntryUpdateSelectionView
self.title: str = _("Network Mismatch")
self.show_back_button: bool = False
self.button_text: str = _("Change Setting")
self.next_destination = Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=SettingsConstants.SETTING__NETWORK), clear_history=True)
super().__post_init__() super().__post_init__()
if not self.text:
# TRANSLATOR_NOTE: Inserts mainnet/testnet/regtest
self.text = _("Current network setting ({}) doesn't match current action.").format(
self.settings.get_value_display_name(SettingsConstants.SETTING__NETWORK),
)
if not self.next_destination: # TRANSLATOR_NOTE: Inserts mainnet/testnet/regtest and derivation path
from seedsigner.views.settings_views import SettingsEntryUpdateSelectionView self.text = _("Current network setting ({}) doesn't match {}.").format(
self.next_destination = Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=SettingsConstants.SETTING__NETWORK), clear_history=True) self.settings.get_value_display_name(SettingsConstants.SETTING__NETWORK),
self.derivation_path,
)
@@ -380,14 +372,12 @@ class UnhandledExceptionView(View):
@dataclass @dataclass
class OptionDisabledView(View): class OptionDisabledView(View):
UPDATE_SETTING = "Update Setting" UPDATE_SETTING = ButtonOption("Update Setting")
DONE = "Done" DONE = ButtonOption("Done")
settings_attr: str settings_attr: str
def __post_init__(self): def __post_init__(self):
super().__post_init__() super().__post_init__()
self.UPDATE_SETTING = _("Update Setting")
self.DONE = _("Done")
self.settings_entry = SettingsDefinition.get_settings_entry(self.settings_attr) self.settings_entry = SettingsDefinition.get_settings_entry(self.settings_attr)
# TRANSLATOR_NOTE: Inserts the name of a settings option (e.g. "Persistent Settings" is currently...) # TRANSLATOR_NOTE: Inserts the name of a settings option (e.g. "Persistent Settings" is currently...)
@@ -413,26 +403,3 @@ class OptionDisabledView(View):
return Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=self.settings_attr), clear_history=True) return Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=self.settings_attr), clear_history=True)
else: else:
return Destination(MainMenuView, clear_history=True) return Destination(MainMenuView, clear_history=True)
class RemoveMicroSDWarningView(View):
"""
Warning to remove the microsd
"""
def __init__(self, next_view: View):
super().__init__()
self.next_view = next_view
def run(self):
self.run_screen(
WarningScreen,
title=_("Security Tip"),
status_icon_name=FontAwesomeIconConstants.SDCARD,
status_headline="",
text=_("For maximum security,\nremove the MicroSD card\nbefore continuing."),
show_back_button=False,
button_data=[_("Continue")],
)
return Destination(self.next_view, clear_history=True)
+1 -1
View File
@@ -295,7 +295,7 @@ def test_generate_screenshots(target_locale):
"Misc Error Views": [ "Misc Error Views": [
NotYetImplementedView, NotYetImplementedView,
(UnhandledExceptionView, dict(error=["IndexError", "line 1, in some_buggy_code.py", "list index out of range"])), (UnhandledExceptionView, dict(error=["IndexError", "line 1, in some_buggy_code.py", "list index out of range"])),
NetworkMismatchErrorView, (NetworkMismatchErrorView, dict(derivation_path="m/84'/1'/0'")),
(OptionDisabledView, dict(settings_attr=SettingsConstants.SETTING__MESSAGE_SIGNING)), (OptionDisabledView, dict(settings_attr=SettingsConstants.SETTING__MESSAGE_SIGNING)),
(ErrorView, dict( (ErrorView, dict(
title="Error", title="Error",
+1 -1
View File
@@ -115,7 +115,7 @@ class TestPSBTFlows(FlowTest):
FlowStep(psbt_views.PSBTSigningErrorView, button_data_selection=psbt_views.PSBTSigningErrorView.SELECT_DIFF_SEED), FlowStep(psbt_views.PSBTSigningErrorView, button_data_selection=psbt_views.PSBTSigningErrorView.SELECT_DIFF_SEED),
FlowStep(psbt_views.PSBTSelectSeedView, button_data_selection=psbt_views.PSBTSelectSeedView.SCAN_SEED), FlowStep(psbt_views.PSBTSelectSeedView, button_data_selection=psbt_views.PSBTSelectSeedView.SCAN_SEED),
FlowStep(scan_views.ScanSeedQRView, before_run=load_seed_into_decoder), FlowStep(scan_views.ScanSeedQRView, before_run=load_seed_into_decoder),
FlowStep(seed_views.SeedFinalizeView, button_data_selection=SettingsConstants.LABEL__BIP39_PASSPHRASE), FlowStep(seed_views.SeedFinalizeView, button_data_selection=seed_views.SeedFinalizeView.PASSPHRASE),
FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="abc")), FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="abc")),
FlowStep(seed_views.SeedReviewPassphraseView, button_data_selection=seed_views.SeedReviewPassphraseView.DONE), FlowStep(seed_views.SeedReviewPassphraseView, button_data_selection=seed_views.SeedReviewPassphraseView.DONE),
FlowStep(seed_views.SeedOptionsView, is_redirect=True), FlowStep(seed_views.SeedOptionsView, is_redirect=True),
+23 -12
View File
@@ -5,7 +5,7 @@ import pytest
from base import BaseTest, FlowTest, FlowStep from base import BaseTest, FlowTest, FlowStep
from base import FlowTestInvalidButtonDataSelectionException from base import FlowTestInvalidButtonDataSelectionException
from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON, ButtonOption
from seedsigner.models.settings import Settings, SettingsConstants from seedsigner.models.settings import Settings, SettingsConstants
from seedsigner.models.seed import ElectrumSeed, Seed from seedsigner.models.seed import ElectrumSeed, Seed
from seedsigner.views.view import ErrorView, MainMenuView, OptionDisabledView, View, NetworkMismatchErrorView from seedsigner.views.view import ErrorView, MainMenuView, OptionDisabledView, View, NetworkMismatchErrorView
@@ -40,10 +40,10 @@ class TestSeedFlows(FlowTest):
self.run_sequence([ self.run_sequence([
FlowStep(MainMenuView, button_data_selection=MainMenuView.SCAN), 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(scan_views.ScanView, before_run=load_seed_into_decoder), # simulate read SeedQR; ret val is ignored
FlowStep(seed_views.SeedFinalizeView, button_data_selection=SettingsConstants.LABEL__BIP39_PASSPHRASE), FlowStep(seed_views.SeedFinalizeView, button_data_selection=seed_views.SeedFinalizeView.PASSPHRASE),
FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="muhpassphrase", is_back_button=True)), FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="muhpassphrase", is_back_button=True)),
FlowStep(seed_views.SeedAddPassphraseExitDialogView, button_data_selection=seed_views.SeedAddPassphraseExitDialogView.DISCARD), FlowStep(seed_views.SeedAddPassphraseExitDialogView, button_data_selection=seed_views.SeedAddPassphraseExitDialogView.DISCARD),
FlowStep(seed_views.SeedFinalizeView, button_data_selection=SettingsConstants.LABEL__BIP39_PASSPHRASE), FlowStep(seed_views.SeedFinalizeView, button_data_selection=seed_views.SeedFinalizeView.PASSPHRASE),
FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="muhpassphrase", is_back_button=True)), FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="muhpassphrase", is_back_button=True)),
FlowStep(seed_views.SeedAddPassphraseExitDialogView, button_data_selection=seed_views.SeedAddPassphraseExitDialogView.EDIT), FlowStep(seed_views.SeedAddPassphraseExitDialogView, button_data_selection=seed_views.SeedAddPassphraseExitDialogView.EDIT),
FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="muhpassphrase")), FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="muhpassphrase")),
@@ -183,15 +183,18 @@ class TestSeedFlows(FlowTest):
""" """
Selecting "Export XPUB" from the SeedOptionsView should enter the Export XPUB flow and end at the MainMenuView Selecting "Export XPUB" from the SeedOptionsView should enter the Export XPUB flow and end at the MainMenuView
""" """
def flowtest_standard_xpub(sig_tuple, script_tuple, coord_tuple): def flowtest_standard_xpub(sig_tuple, script_tuple, coord_tuple):
if sig_tuple[0] == SettingsConstants.SINGLE_SIG:
sig_selection = seed_views.SeedExportXpubSigTypeView.SINGLE_SIG
else:
sig_selection = seed_views.SeedExportXpubSigTypeView.MULTISIG
self.run_sequence( self.run_sequence(
initial_destination_view_args=dict(seed_num=0), initial_destination_view_args=dict(seed_num=0),
sequence=[ sequence=[
FlowStep(seed_views.SeedOptionsView, button_data_selection=seed_views.SeedOptionsView.EXPORT_XPUB), FlowStep(seed_views.SeedOptionsView, button_data_selection=seed_views.SeedOptionsView.EXPORT_XPUB),
FlowStep(seed_views.SeedExportXpubSigTypeView, button_data_selection=sig_tuple[1]), FlowStep(seed_views.SeedExportXpubSigTypeView, button_data_selection=sig_selection),
FlowStep(seed_views.SeedExportXpubScriptTypeView, button_data_selection=script_tuple[1]), FlowStep(seed_views.SeedExportXpubScriptTypeView, button_data_selection=ButtonOption(script_tuple[1], return_data=script_tuple[0])),
FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=coord_tuple[1]), FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=ButtonOption(coord_tuple[1], return_data=coord_tuple[0])),
FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0),
FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0),
FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0),
@@ -303,10 +306,18 @@ class TestSeedFlows(FlowTest):
SettingsConstants.CUSTOM_DERIVATION SettingsConstants.CUSTOM_DERIVATION
]) ])
# get display names to access button choices in the views (ugh: hardcoding, is there a better way?) # Ensure that all coordinators are enabled
sig_type = self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__SIG_TYPES)[0] # single sig self.settings.set_value(SettingsConstants.SETTING__COORDINATORS, [x for x, y in SettingsConstants.ALL_COORDINATORS])
script_type = self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__SCRIPT_TYPES)[2] # custom derivation
coordinator = self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS)[3] # specter # Set up button_data selections
sig_type = seed_views.SeedExportXpubSigTypeView.SINGLE_SIG
custom_derivation = SettingsConstants.CUSTOM_DERIVATION
script_type = ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__SCRIPT_TYPES)[2], return_data=custom_derivation)
specter = SettingsConstants.COORDINATOR__SPECTER_DESKTOP
assert SettingsConstants.ALL_COORDINATORS[3][0] == specter
coordinator = ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS)[3], return_data=specter)
self.run_sequence( self.run_sequence(
initial_destination_view_args=dict(seed_num=0), initial_destination_view_args=dict(seed_num=0),
@@ -377,7 +388,7 @@ class TestSeedFlows(FlowTest):
# Skips past the script type options via redirect # Skips past the script type options via redirect
FlowStep(seed_views.SeedExportXpubScriptTypeView, is_redirect=True), FlowStep(seed_views.SeedExportXpubScriptTypeView, is_redirect=True),
FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS)[0]), FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS)[0], return_data=SettingsConstants.ALL_COORDINATORS[0][0])),
FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0),
FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0),
FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0),
+4 -4
View File
@@ -8,7 +8,7 @@ from base import FlowTest, FlowStep
from seedsigner.models.settings import Settings from seedsigner.models.settings import Settings
from seedsigner.models.settings_definition import SettingsDefinition, SettingsConstants from seedsigner.models.settings_definition import SettingsDefinition, SettingsConstants
from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON, ButtonOption
from seedsigner.hardware.microsd import MicroSD from seedsigner.hardware.microsd import MicroSD
from seedsigner.views.view import MainMenuView from seedsigner.views.view import MainMenuView
from seedsigner.views import scan_views, settings_views from seedsigner.views import scan_views, settings_views
@@ -26,8 +26,8 @@ class TestSettingsFlows(FlowTest):
self.run_sequence([ self.run_sequence([
FlowStep(MainMenuView, button_data_selection=MainMenuView.SETTINGS), FlowStep(MainMenuView, button_data_selection=MainMenuView.SETTINGS),
FlowStep(settings_views.SettingsMenuView, button_data_selection=settings_entry.display_name), FlowStep(settings_views.SettingsMenuView, button_data_selection=ButtonOption(settings_entry.display_name)),
FlowStep(settings_views.SettingsEntryUpdateSelectionView, button_data_selection=settings_entry.get_selection_option_display_name_by_value(SettingsConstants.OPTION__ENABLED)), FlowStep(settings_views.SettingsEntryUpdateSelectionView, button_data_selection=ButtonOption(settings_entry.get_selection_option_display_name_by_value(SettingsConstants.OPTION__ENABLED))),
FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=RET_CODE__BACK_BUTTON), FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=RET_CODE__BACK_BUTTON),
FlowStep(settings_views.SettingsMenuView), FlowStep(settings_views.SettingsMenuView),
]) ])
@@ -43,7 +43,7 @@ class TestSettingsFlows(FlowTest):
self.run_sequence([ self.run_sequence([
FlowStep(MainMenuView, button_data_selection=MainMenuView.SETTINGS), FlowStep(MainMenuView, button_data_selection=MainMenuView.SETTINGS),
FlowStep(settings_views.SettingsMenuView, button_data_selection=settings_entry.display_name), FlowStep(settings_views.SettingsMenuView, button_data_selection=ButtonOption(settings_entry.display_name)),
FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=0), # select/deselect first option FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=0), # select/deselect first option
FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=1), # select/deselect second option FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=1), # select/deselect second option
FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=1), # select/deselect second option FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=1), # select/deselect second option
+3 -3
View File
@@ -2,7 +2,7 @@
from base import FlowTest, FlowStep from base import FlowTest, FlowStep
from seedsigner.controller import Controller from seedsigner.controller import Controller
from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON, ButtonOption
from seedsigner.models.seed import Seed from seedsigner.models.seed import Seed
from seedsigner.models.settings_definition import SettingsConstants, SettingsDefinition from seedsigner.models.settings_definition import SettingsConstants, SettingsDefinition
from seedsigner.views.view import ErrorView, MainMenuView from seedsigner.views.view import ErrorView, MainMenuView
@@ -25,7 +25,7 @@ class TestToolsFlows(FlowTest):
FlowStep(MainMenuView, button_data_selection=MainMenuView.TOOLS), FlowStep(MainMenuView, button_data_selection=MainMenuView.TOOLS),
FlowStep(tools_views.ToolsMenuView, button_data_selection=tools_views.ToolsMenuView.ADDRESS_EXPLORER), FlowStep(tools_views.ToolsMenuView, button_data_selection=tools_views.ToolsMenuView.ADDRESS_EXPLORER),
FlowStep(tools_views.ToolsAddressExplorerSelectSourceView, screen_return_value=0), # ret 1st onboard seed FlowStep(tools_views.ToolsAddressExplorerSelectSourceView, screen_return_value=0), # ret 1st onboard seed
FlowStep(seed_views.SeedExportXpubScriptTypeView, button_data_selection=SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__SCRIPT_TYPES).get_selection_option_display_name_by_value(SettingsConstants.NATIVE_SEGWIT)), FlowStep(seed_views.SeedExportXpubScriptTypeView, button_data_selection=ButtonOption(SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__SCRIPT_TYPES).get_selection_option_display_name_by_value(SettingsConstants.NATIVE_SEGWIT), return_data=SettingsConstants.NATIVE_SEGWIT)),
FlowStep(tools_views.ToolsAddressExplorerAddressTypeView, button_data_selection=tools_views.ToolsAddressExplorerAddressTypeView.RECEIVE), FlowStep(tools_views.ToolsAddressExplorerAddressTypeView, button_data_selection=tools_views.ToolsAddressExplorerAddressTypeView.RECEIVE),
FlowStep(tools_views.ToolsAddressExplorerAddressListView, screen_return_value=10), # ret NEXT page of addrs FlowStep(tools_views.ToolsAddressExplorerAddressListView, screen_return_value=10), # ret NEXT page of addrs
FlowStep(tools_views.ToolsAddressExplorerAddressListView, screen_return_value=4), # ret a specific addr from the list FlowStep(tools_views.ToolsAddressExplorerAddressListView, screen_return_value=4), # ret a specific addr from the list
@@ -62,7 +62,7 @@ class TestToolsFlows(FlowTest):
# Finalize the new seed w/passphrase # Finalize the new seed w/passphrase
self.run_sequence( self.run_sequence(
sequence=[ sequence=[
FlowStep(seed_views.SeedFinalizeView, button_data_selection=SettingsConstants.LABEL__BIP39_PASSPHRASE), FlowStep(seed_views.SeedFinalizeView, button_data_selection=seed_views.SeedFinalizeView.PASSPHRASE),
FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="mypassphrase")), FlowStep(seed_views.SeedAddPassphraseView, screen_return_value=dict(passphrase="mypassphrase")),
FlowStep(seed_views.SeedReviewPassphraseView, button_data_selection=seed_views.SeedReviewPassphraseView.DONE), FlowStep(seed_views.SeedReviewPassphraseView, button_data_selection=seed_views.SeedReviewPassphraseView.DONE),
FlowStep(seed_views.SeedOptionsView, is_redirect=True), FlowStep(seed_views.SeedOptionsView, is_redirect=True),