diff --git a/l10n/messages.pot b/l10n/messages.pot index 5f147efe..11bd6ee0 100644 --- a/l10n/messages.pot +++ b/l10n/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: seedsigner 0.8.5\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" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -151,9 +151,6 @@ msgstr[1] "" msgid "{} change" 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/models/settings_definition.py #: src/seedsigner/views/seed_views.py @@ -164,6 +161,7 @@ msgstr "" msgid "Change" msgstr "" +#. Abbreviation for receive address #: src/seedsigner/gui/screens/psbt_screens.py msgid "Addr" msgstr "" @@ -263,6 +261,7 @@ msgstr "" #. 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/tools_screens.py +#: src/seedsigner/views/seed_views.py msgid "fingerprint" msgstr "" @@ -817,7 +816,7 @@ msgid "" "addresses." msgstr "" -#: src/seedsigner/views/psbt_views.py src/seedsigner/views/view.py +#: src/seedsigner/views/psbt_views.py msgid "Continue" msgstr "" @@ -1295,11 +1294,6 @@ msgstr "" msgid "Return to PSBT" 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 msgid "Signing messages for custom derivation paths not supported" msgstr "" @@ -1470,9 +1464,9 @@ msgstr "" msgid "Change Setting" msgstr "" -#. Inserts mainnet/testnet/regtest +#. Inserts mainnet/testnet/regtest and derivation path #: src/seedsigner/views/view.py -msgid "Current network setting ({}) doesn't match current action." +msgid "Current network setting ({}) doesn't match {}." msgstr "" #: src/seedsigner/views/view.py @@ -1493,14 +1487,3 @@ msgstr "" msgid "Option Disabled" 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 "" - diff --git a/setup.cfg b/setup.cfg index b777f178..d2b32822 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,5 @@ [extract_messages] +keywords = _ _mft mark_for_translation ButtonOption add_comments = TRANSLATOR_NOTE: strip_comments = yes add_location = file diff --git a/src/seedsigner/gui/screens/psbt_screens.py b/src/seedsigner/gui/screens/psbt_screens.py index 7546e619..c64855c6 100644 --- a/src/seedsigner/gui/screens/psbt_screens.py +++ b/src/seedsigner/gui/screens/psbt_screens.py @@ -11,7 +11,7 @@ from seedsigner.gui.components import (BtcAmount, Icon, FontAwesomeIconConstants from seedsigner.gui.renderer import Renderer from seedsigner.models.threads import BaseThread -from .screen import ButtonListScreen +from .screen import ButtonListScreen, ButtonOption @@ -31,7 +31,7 @@ class PSBTOverviewScreen(ButtonListScreen): # Customize defaults self.title = _("Review PSBT") 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 self.show_loading_screen = True @@ -479,7 +479,7 @@ class PSBTMathScreen(ButtonListScreen): def __post_init__(self): # Customize defaults self.title = _("PSBT Math") - self.button_data = [_("Review Recipients")] + self.button_data = [ButtonOption("Review Recipients")] self.is_bottom_list = True 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 + + 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( - # 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="""{}: {} #{}""".format(_("Multisig") if self.is_multisig else self.fingerprint, _("Change") if self.is_change_derivation_path else _("Addr"), self.derivation_path_addr_index), + value_text=value_text, icon_name=SeedSignerIconConstants.FINGERPRINT, icon_color=GUIConstants.INFO_COLOR, is_text_centered=False, diff --git a/src/seedsigner/gui/screens/screen.py b/src/seedsigner/gui/screens/screen.py index 74f99b5b..ff96c80e 100644 --- a/src/seedsigner/gui/screens/screen.py +++ b/src/seedsigner/gui/screens/screen.py @@ -5,6 +5,7 @@ from gettext import gettext as _ from PIL import Image, ImageDraw, ImageColor from typing import Any, List, Tuple +from seedsigner.helpers.l10n import mark_for_translation as _mft from seedsigner.gui.components import (GUIConstants, BaseComponent, Button, Icon, IconButton, LargeIconButton, 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 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 is_button_text_centered: bool = True is_bottom_list: bool = False @@ -295,26 +310,38 @@ class ButtonListScreen(BaseTopNavScreen): self.has_scroll_arrows = True 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_color = None right_icon_name = None button_label_color = None - # TODO: Define an actual class for button_data? - if type(button_label) == tuple: - if len(button_label) == 2: - (button_label, icon_name) = button_label - icon_color = GUIConstants.BUTTON_FONT_COLOR + if type(button_option) == ButtonOption: + button_label = button_option.button_label + icon_name = button_option.icon_name + icon_color = button_option.icon_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: - (button_label, icon_name, icon_color) = button_label + # # TODO: Complete refactor away from str|tuple to ButtonOption + # 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: - (button_label, icon_name, icon_color, button_label_color) = button_label + # elif len(button_option) == 3: + # (button_label, icon_name, icon_color) = button_option - elif len(button_label) == 5: - (button_label, icon_name, icon_color, button_label_color, right_icon_name) = button_label + # elif len(button_option) == 4: + # (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( 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) self.buttons = [] - for i, button_label in enumerate(self.button_data): - if type(button_label) == tuple: - (button_label, icon_name) = button_label + for i, button_option in enumerate(self.button_data): + if type(button_option) == ButtonOption: + button_label = button_option.button_label + icon_name = button_option.icon_name 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: button_start_x = GUIConstants.EDGE_PADDING @@ -848,18 +884,20 @@ class QRDisplayScreen(BaseScreen): @dataclass class LargeIconStatusScreen(ButtonListScreen): - title: str = _("Success!") + title: str = _mft("Success!") status_icon_name: str = SeedSignerIconConstants.SUCCESS status_icon_size: int = GUIConstants.ICON_PRIMARY_SCREEN_SIZE status_color: str = GUIConstants.SUCCESS_COLOR status_headline: str = None text: str = "" # The body text of the screen text_edge_padding: int = GUIConstants.EDGE_PADDING - button_data: list = field(default_factory=lambda: [_("OK")]) + button_data: list = None allow_text_overflow: bool = False def __post_init__(self): + if not self.button_data: + self.button_data = [ButtonOption("OK")] self.is_bottom_list = True super().__post_init__() @@ -971,17 +1009,17 @@ class WarningEdgesMixin: @dataclass class WarningScreen(WarningEdgesMixin, LargeIconStatusScreen): - title: str = _("Caution") + title: str = _mft("Caution") status_icon_name: str = SeedSignerIconConstants.WARNING status_color: str = "yellow" - status_headline: str = _("Privacy Leak!") # The colored text under the alert icon - button_data: list = field(default_factory=lambda: [_("I Understand")]) + status_headline: str = _mft("Privacy Leak!") # The colored text under the alert icon + button_data: list = field(default_factory=lambda: [ButtonOption("I Understand")]) @dataclass 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 diff --git a/src/seedsigner/gui/screens/seed_screens.py b/src/seedsigner/gui/screens/seed_screens.py index 54e07454..78bc6428 100644 --- a/src/seedsigner/gui/screens/seed_screens.py +++ b/src/seedsigner/gui/screens/seed_screens.py @@ -11,7 +11,7 @@ from seedsigner.gui.renderer import Renderer from seedsigner.helpers.qr import QR 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, IconTextLine, SeedSignerIconConstants, TextArea, GUIConstants, reflow_text_into_pages) @@ -607,7 +607,7 @@ class SeedExportXpubDetailsScreen(WarningEdgesMixin, ButtonListScreen): def __post_init__(self): # Programmatically set up other args - self.button_data = [_("Export Xpub")] + self.button_data = [ButtonOption("Export Xpub")] self.title = _("Xpub Details") # Initialize the base class @@ -1138,7 +1138,8 @@ class SeedTranscribeSeedQRWholeQRScreen(WarningEdgesMixin, ButtonListScreen): def __post_init__(self): self.title = _("Transcribe SeedQR") # 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.status_color = GUIConstants.DIRE_WARNING_COLOR 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.is_bottom_list = True self.is_button_text_centered = True - self.button_data = [_("Next")] + self.button_data = [ButtonOption("Next")] super().__post_init__() message_display = TextArea( @@ -1586,7 +1587,7 @@ class SeedSignMessageConfirmAddressScreen(ButtonListScreen): self.title = _("Confirm Address") self.is_bottom_list = True self.is_button_text_centered = True - self.button_data = [_("Sign Message")] + self.button_data = [ButtonOption("Sign Message")] super().__post_init__() derivation_path_display = IconTextLine( diff --git a/src/seedsigner/gui/screens/settings_screens.py b/src/seedsigner/gui/screens/settings_screens.py index cf014f7a..be62859d 100644 --- a/src/seedsigner/gui/screens/settings_screens.py +++ b/src/seedsigner/gui/screens/settings_screens.py @@ -5,9 +5,10 @@ from gettext import gettext as _ from PIL.ImageOps import autocontrast 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.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.camera import Camera from seedsigner.models.settings import SettingsConstants @@ -309,13 +310,13 @@ class DonateScreen(BaseTopNavScreen): @dataclass class SettingsQRConfirmationScreen(ButtonListScreen): config_name: str = None - title: str = _("Settings QR") - status_message: str = _("Settings updated...") + title: str = _mft("Settings QR") + status_message: str = _mft("Settings updated...") is_bottom_list: bool = True def __post_init__(self): # Customize defaults - self.button_data = [_("Home")] + self.button_data = [ButtonOption("Home")] self.show_back_button = False super().__post_init__() diff --git a/src/seedsigner/helpers/embit_utils.py b/src/seedsigner/helpers/embit_utils.py index 7e260aa4..1754b080 100644 --- a/src/seedsigner/helpers/embit_utils.py +++ b/src/seedsigner/helpers/embit_utils.py @@ -50,7 +50,7 @@ def get_standard_derivation_path(network: str = SettingsConstants.MAINNET, walle elif script_type == SettingsConstants.NATIVE_SEGWIT: return f"m/48'/{network_path}/0'/2'" elif script_type == SettingsConstants.TAPROOT: - raise Exception("Taproot multisig/musig not yet supported") + raise Exception("Taproot multisig not yet supported") else: raise Exception("Unexpected script type") else: diff --git a/src/seedsigner/helpers/l10n.py b/src/seedsigner/helpers/l10n.py new file mode 100644 index 00000000..a971da58 --- /dev/null +++ b/src/seedsigner/helpers/l10n.py @@ -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 \ No newline at end of file diff --git a/src/seedsigner/models/settings_definition.py b/src/seedsigner/models/settings_definition.py index a6fa8200..6fa1abaf 100644 --- a/src/seedsigner/models/settings_definition.py +++ b/src/seedsigner/models/settings_definition.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Any, List -from gettext import gettext as _ +from seedsigner.helpers.l10n import mark_for_translation as _mft class SettingsConstants: @@ -11,25 +11,25 @@ class SettingsConstants: OPTION__PROMPT = "P" OPTION__REQUIRED = "R" OPTIONS__ENABLED_DISABLED = [ - (OPTION__ENABLED, _("Enabled")), - (OPTION__DISABLED, _("Disabled")), + (OPTION__ENABLED, _mft("Enabled")), + (OPTION__DISABLED, _mft("Disabled")), ] OPTIONS__ONLY_DISABLED = [ - (OPTION__DISABLED, _("Disabled")), + (OPTION__DISABLED, _mft("Disabled")), ] OPTIONS__PROMPT_REQUIRED_DISABLED = [ - (OPTION__PROMPT, _("Prompt")), - (OPTION__REQUIRED, _("Required")), - (OPTION__DISABLED, _("Disabled")), + (OPTION__PROMPT, _mft("Prompt")), + (OPTION__REQUIRED, _mft("Required")), + (OPTION__DISABLED, _mft("Disabled")), ] OPTIONS__ENABLED_DISABLED_REQUIRED = OPTIONS__ENABLED_DISABLED +[ - (OPTION__REQUIRED, _("Required")), + (OPTION__REQUIRED, _mft("Required")), ] OPTIONS__ENABLED_DISABLED_PROMPT = OPTIONS__ENABLED_DISABLED + [ - (OPTION__PROMPT, _("Prompt")), + (OPTION__PROMPT, _mft("Prompt")), ] ALL_OPTIONS = OPTIONS__ENABLED_DISABLED_PROMPT + [ - (OPTION__REQUIRED, _("Required")), + (OPTION__REQUIRED, _mft("Required")), ] # User-facing selection options @@ -77,10 +77,10 @@ class SettingsConstants: BTC_DENOMINATION__THRESHOLD = "thr" BTC_DENOMINATION__BTCSATSHYBRID = "hyb" ALL_BTC_DENOMINATIONS = [ - (BTC_DENOMINATION__BTC, _("BTC")), - (BTC_DENOMINATION__SATS, _("sats")), - (BTC_DENOMINATION__THRESHOLD, _("Threshold at 0.01")), - (BTC_DENOMINATION__BTCSATSHYBRID, _("BTC | sats hybrid")), + (BTC_DENOMINATION__BTC, _mft("BTC")), + (BTC_DENOMINATION__SATS, _mft("sats")), + (BTC_DENOMINATION__THRESHOLD, _mft("Threshold at 0.01")), + (BTC_DENOMINATION__BTCSATSHYBRID, _mft("BTC | sats hybrid")), ] CAMERA_ROTATION__0 = 0 @@ -88,10 +88,10 @@ class SettingsConstants: CAMERA_ROTATION__180 = 180 CAMERA_ROTATION__270 = 270 ALL_CAMERA_ROTATIONS = [ - (CAMERA_ROTATION__0, _("0°")), - (CAMERA_ROTATION__90, _("90°")), - (CAMERA_ROTATION__180, _("180°")), - (CAMERA_ROTATION__270, _("270°")), + (CAMERA_ROTATION__0, _mft("0°")), + (CAMERA_ROTATION__90, _mft("90°")), + (CAMERA_ROTATION__180, _mft("180°")), + (CAMERA_ROTATION__270, _mft("270°")), ] # QR code constants @@ -99,11 +99,11 @@ class SettingsConstants: DENSITY__MEDIUM = "M" DENSITY__HIGH = "H" # 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 - density_medium = _("Medium") + density_medium = _mft("Medium") # TRANSLATOR_NOTE: QR code density option: Low, Medium, High - density_high = _("High") + density_high = _mft("High") ALL_DENSITIES = [ (DENSITY__LOW, density_low), (DENSITY__MEDIUM, density_medium), @@ -115,9 +115,9 @@ class SettingsConstants: TESTNET = "T" REGTEST = "R" ALL_NETWORKS = [ - (MAINNET, _("Mainnet")), - (TESTNET, _("Testnet")), - (REGTEST, _("Regtest")) + (MAINNET, _mft("Mainnet")), + (TESTNET, _mft("Testnet")), + (REGTEST, _mft("Regtest")) ] @classmethod @@ -130,14 +130,14 @@ class SettingsConstants: if network == SettingsConstants.REGTEST: return "regtest" - PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT = _("Store Settings on SD card") - PERSISTENT_SETTINGS__SD_REMOVED__HELP_TEXT = _("Insert SD card to enable") + PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT = _mft("Store Settings on SD card") + PERSISTENT_SETTINGS__SD_REMOVED__HELP_TEXT = _mft("Insert SD card to enable") SINGLE_SIG = "ss" MULTISIG = "ms" ALL_SIG_TYPES = [ - (SINGLE_SIG, _("Single Sig")), - (MULTISIG, _("Multisig")), + (SINGLE_SIG, _mft("Single Sig")), + (MULTISIG, _mft("Multisig")), ] LEGACY_P2PKH = "leg" @@ -146,11 +146,11 @@ class SettingsConstants: TAPROOT = "tr" CUSTOM_DERIVATION = "cus" ALL_SCRIPT_TYPES = [ - (NATIVE_SEGWIT, _("Native Segwit")), - (NESTED_SEGWIT, _("Nested Segwit")), - (LEGACY_P2PKH, _("Legacy")), - (TAPROOT, _("Taproot")), - (CUSTOM_DERIVATION, _("Custom Derivation")), + (NATIVE_SEGWIT, _mft("Native Segwit")), + (NESTED_SEGWIT, _mft("Nested Segwit")), + (LEGACY_P2PKH, _mft("Legacy")), + (TAPROOT, _mft("Taproot")), + (CUSTOM_DERIVATION, _mft("Custom Derivation")), ] WORDLIST_LANGUAGE__ENGLISH = "en" @@ -237,9 +237,9 @@ class SettingsConstants: ELECTRUM_PBKDF2_ROUNDS=2048 # 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 - custom_extension = _("Custom Extension") + custom_extension = _mft("Custom Extension") LABEL__CUSTOM_EXTENSION = custom_extension @@ -311,7 +311,7 @@ class SettingsEntry: option_value = option display_name = option if option_value == value: - return _(display_name) + return _mft(display_name) def get_selection_option_value_by_display_name(self, display_name: str): @@ -380,7 +380,7 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, attr_name=SettingsConstants.SETTING__LOCALE, abbreviated_name="lang", - display_name=_("Language"), + display_name=_mft("Language"), type=SettingsConstants.TYPE__SELECT_1, selection_options=SettingsConstants.ALL_LOCALES, default_value=SettingsConstants.LOCALE__ENGLISH), @@ -389,7 +389,7 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, attr_name=SettingsConstants.SETTING__WORDLIST_LANGUAGE, abbreviated_name="wordlist_lang", - display_name=_("Mnemonic language"), + display_name=_mft("Mnemonic language"), type=SettingsConstants.TYPE__SELECT_1, visibility=SettingsConstants.VISIBILITY__HIDDEN, selection_options=SettingsConstants.ALL_WORDLIST_LANGUAGES, @@ -398,14 +398,14 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, attr_name=SettingsConstants.SETTING__PERSISTENT_SETTINGS, abbreviated_name="persistent", - display_name=_("Persistent settings"), + display_name=_mft("Persistent settings"), help_text=SettingsConstants.PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT, default_value=SettingsConstants.OPTION__DISABLED), SettingsEntry(category=SettingsConstants.CATEGORY__WALLET, attr_name=SettingsConstants.SETTING__COORDINATORS, abbreviated_name="coords", - display_name=_("Coordinator software"), + display_name=_mft("Coordinator software"), type=SettingsConstants.TYPE__MULTISELECT, selection_options=SettingsConstants.ALL_COORDINATORS, default_value=[ @@ -418,7 +418,7 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, attr_name=SettingsConstants.SETTING__BTC_DENOMINATION, abbreviated_name="denom", - display_name=_("Denomination display"), + display_name=_mft("Denomination display"), type=SettingsConstants.TYPE__SELECT_1, selection_options=SettingsConstants.ALL_BTC_DENOMINATIONS, default_value=SettingsConstants.BTC_DENOMINATION__THRESHOLD), @@ -427,7 +427,7 @@ class SettingsDefinition: # Advanced options SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__NETWORK, - display_name=_("Bitcoin network"), + display_name=_mft("Bitcoin network"), type=SettingsConstants.TYPE__SELECT_1, visibility=SettingsConstants.VISIBILITY__ADVANCED, selection_options=SettingsConstants.ALL_NETWORKS, @@ -435,7 +435,7 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__QR_DENSITY, - display_name=_("QR code density"), + display_name=_mft("QR code density"), type=SettingsConstants.TYPE__SELECT_1, visibility=SettingsConstants.VISIBILITY__ADVANCED, selection_options=SettingsConstants.ALL_DENSITIES, @@ -443,14 +443,14 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__XPUB_EXPORT, - display_name=_("Xpub export"), + display_name=_mft("Xpub export"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__ENABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__SIG_TYPES, abbreviated_name="sigs", - display_name=_("Sig types"), + display_name=_mft("Sig types"), type=SettingsConstants.TYPE__MULTISELECT, visibility=SettingsConstants.VISIBILITY__ADVANCED, selection_options=SettingsConstants.ALL_SIG_TYPES, @@ -459,7 +459,7 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__SCRIPT_TYPES, abbreviated_name="scripts", - display_name=_("Script types"), + display_name=_mft("Script types"), type=SettingsConstants.TYPE__MULTISELECT, visibility=SettingsConstants.VISIBILITY__ADVANCED, selection_options=SettingsConstants.ALL_SCRIPT_TYPES, @@ -467,13 +467,13 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__XPUB_DETAILS, - display_name=_("Show xpub details"), + display_name=_mft("Show xpub details"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__ENABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__PASSPHRASE, - display_name=_("BIP-39 passphrase"), + display_name=_mft("BIP-39 passphrase"), type=SettingsConstants.TYPE__SELECT_1, visibility=SettingsConstants.VISIBILITY__ADVANCED, selection_options=SettingsConstants.OPTIONS__ENABLED_DISABLED_REQUIRED, @@ -482,7 +482,7 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__CAMERA_ROTATION, abbreviated_name="camera", - display_name=_("Camera rotation"), + display_name=_mft("Camera rotation"), type=SettingsConstants.TYPE__SELECT_1, visibility=SettingsConstants.VISIBILITY__ADVANCED, selection_options=SettingsConstants.ALL_CAMERA_ROTATIONS, @@ -490,14 +490,14 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__COMPACT_SEEDQR, - display_name=_("Compact SeedQR"), + display_name=_mft("Compact SeedQR"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__ENABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__BIP85_CHILD_SEEDS, abbreviated_name="bip85", - display_name=_("BIP-85 child seeds"), + display_name=_mft("BIP-85 child seeds"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__DISABLED), @@ -505,40 +505,40 @@ class SettingsDefinition: attr_name=SettingsConstants.SETTING__ELECTRUM_SEEDS, abbreviated_name="electrum", display_name="Electrum seeds", - help_text=_("Native Segwit only"), + help_text=_mft("Native Segwit only"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__DISABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__MESSAGE_SIGNING, - display_name=_("Message signing"), + display_name=_mft("Message signing"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__DISABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__PRIVACY_WARNINGS, abbreviated_name="priv_warn", - display_name=_("Show privacy warnings"), + display_name=_mft("Show privacy warnings"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__ENABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__DIRE_WARNINGS, abbreviated_name="dire_warn", - display_name=_("Show dire warnings"), + display_name=_mft("Show dire warnings"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__ENABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__QR_BRIGHTNESS_TIPS, - display_name=_("Show QR brightness tips"), + display_name=_mft("Show QR brightness tips"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__ENABLED), SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__PARTNER_LOGOS, abbreviated_name="partners", - display_name=_("Show partner logos"), + display_name=_mft("Show partner logos"), visibility=SettingsConstants.VISIBILITY__ADVANCED, default_value=SettingsConstants.OPTION__ENABLED), @@ -554,7 +554,7 @@ class SettingsDefinition: SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, attr_name=SettingsConstants.SETTING__QR_BRIGHTNESS, abbreviated_name="qr_brightness", - display_name=_("QR background color"), + display_name=_mft("QR background color"), type=SettingsConstants.TYPE__FREE_ENTRY, visibility=SettingsConstants.VISIBILITY__HIDDEN, default_value=62), diff --git a/src/seedsigner/views/psbt_views.py b/src/seedsigner/views/psbt_views.py index 700bb2bd..636751d1 100644 --- a/src/seedsigner/views/psbt_views.py +++ b/src/seedsigner/views/psbt_views.py @@ -3,16 +3,16 @@ from gettext import gettext as _ from seedsigner.models.psbt_parser import PSBTParser from seedsigner.models.settings import SettingsConstants 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 class PSBTSelectSeedView(View): - SCAN_SEED = (_("Scan a seed"), SeedSignerIconConstants.QRCODE) - TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) + SCAN_SEED = ButtonOption("Scan a seed", SeedSignerIconConstants.QRCODE) + TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD) + TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD) + TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD) 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 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.TYPE_12WORD) @@ -169,7 +169,7 @@ class PSBTUnsupportedScriptTypeWarningView(View): selected_menu_num = WarningScreen( status_headline=_("Unsupported Script Type!"), text=_("PSBT has unsupported input script type, please verify your change addresses."), - button_data=[_("Continue")], + button_data=[ButtonOption("Continue")], ).display() 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 status_headline=_("Full Spend!"), text=_("This PSBT spends its entire input value. No change is coming back to your wallet."), - button_data=[_("Continue")], + button_data=[ButtonOption("Continue")], ).display() if selected_menu_num == RET_CODE__BACK_BUTTON: @@ -265,10 +265,10 @@ class PSBTAddressDetailsView(View): button_data = [] if self.address_num < psbt_parser.num_destinations - 1: - button_data.append(_("Next Recipient")) + button_data.append(ButtonOption("Next Recipient")) else: # TRANSLATOR_NOTE: Short for "Next step" - button_data.append(_("Next")) + button_data.append(ButtonOption("Next")) selected_menu_num = self.run_screen( PSBTAddressDetailsScreen, @@ -299,10 +299,9 @@ class PSBTAddressDetailsView(View): class PSBTChangeDetailsView(View): - NEXT = _("Next") - SKIP_VERIFICATION = _("Skip Verification") - VERIFY_MULTISIG = _("Verify Multisig Change") - + NEXT = ButtonOption("Next") + SKIP_VERIFICATION = ButtonOption("Skip Verification") + VERIFY_MULTISIG = ButtonOption("Verify Multisig Change") def __init__(self, change_address_num): super().__init__() @@ -349,7 +348,7 @@ class PSBTChangeDetailsView(View): title = _("Your Change") else: title = _("Self-Transfer") - self.VERIFY_MULTISIG = _("Verify Multisig Addr") + self.VERIFY_MULTISIG.button_label = _("Verify Multisig Addr") # if psbt_parser.num_change_outputs > 1: # title += f" (#{self.change_address_num + 1})" @@ -473,7 +472,7 @@ class PSBTAddressVerificationFailedView(View): title=title, status_headline=_("Address Verification Failed"), text=text, - button_data=[_("Discard PSBT")], + button_data=[ButtonOption("Discard PSBT")], show_back_button=False, ).display() @@ -495,8 +494,8 @@ class PSBTOpReturnView(View): # Should not be able to get here raise Exception("Routing error") - title = "OP_RETURN" - button_data = ["Next"] + title = _("OP_RETURN") + button_data = [ButtonOption("Next")] selected_menu_num = self.run_screen( PSBTOpReturnScreen, @@ -515,7 +514,7 @@ class PSBTOpReturnView(View): class PSBTFinalizeView(View): """ """ - APPROVE_PSBT = "Approve PSBT" + APPROVE_PSBT = ButtonOption("Approve PSBT") def run(self): @@ -524,7 +523,6 @@ class PSBTFinalizeView(View): psbt_parser: PSBTParser = self.controller.psbt_parser psbt: PSBT = self.controller.psbt - self.APPROVE_PSBT = _("Approve PSBT") if not psbt_parser: # Should not be able to get here @@ -573,7 +571,7 @@ class PSBTSignedQRDisplayView(View): class PSBTSigningErrorView(View): - SELECT_DIFF_SEED = _("Select Diff Seed") + SELECT_DIFF_SEED = ButtonOption("Select Diff Seed") def run(self): psbt_parser: PSBTParser = self.controller.psbt_parser diff --git a/src/seedsigner/views/scan_views.py b/src/seedsigner/views/scan_views.py index bf14a3cb..aa83c6bd 100644 --- a/src/seedsigner/views/scan_views.py +++ b/src/seedsigner/views/scan_views.py @@ -2,7 +2,7 @@ import logging import re from gettext import gettext as _ - +from seedsigner.helpers.l10n import mark_for_translation as _mft from seedsigner.models.settings import SettingsConstants 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 selected but a SeedQR was scanned). """ - instructions_text = _("Scan a QR code") - invalid_qr_type_message = _("QRCode not recognized or not yet supported.") + instructions_text = _mft("Scan a QR code") + invalid_qr_type_message = _mft("QRCode not recognized or not yet supported.") def __init__(self): @@ -176,8 +176,8 @@ class ScanView(View): class ScanPSBTView(ScanView): - instructions_text = _("Scan PSBT") - invalid_qr_type_message = _("Expected a PSBT") + instructions_text = _mft("Scan PSBT") + invalid_qr_type_message = _mft("Expected a PSBT") @property def is_valid_qr_type(self): @@ -186,8 +186,8 @@ class ScanPSBTView(ScanView): class ScanSeedQRView(ScanView): - instructions_text = _("Scan SeedQR") - invalid_qr_type_message = _("Expected a SeedQR") + instructions_text = _mft("Scan SeedQR") + invalid_qr_type_message = _mft("Expected a SeedQR") @property def is_valid_qr_type(self): @@ -196,8 +196,8 @@ class ScanSeedQRView(ScanView): class ScanWalletDescriptorView(ScanView): - instructions_text = _("Scan descriptor") - invalid_qr_type_message = _("Expected a wallet descriptor QR") + instructions_text = _mft("Scan descriptor") + invalid_qr_type_message = _mft("Expected a wallet descriptor QR") @property def is_valid_qr_type(self): @@ -206,8 +206,8 @@ class ScanWalletDescriptorView(ScanView): class ScanAddressView(ScanView): - instructions_text = _("Scan address QR") - invalid_qr_type_message = _("Expected an address QR") + instructions_text = _mft("Scan address QR") + invalid_qr_type_message = _mft("Expected an address QR") @property def is_valid_qr_type(self): diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index 014dd138..89c58cca 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -10,6 +10,7 @@ from embit.descriptor import Descriptor from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, 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.qr_type import QRType from seedsigner.models.seed import Seed @@ -23,7 +24,7 @@ logger = logging.getLogger(__name__) class SeedsMenuView(View): - LOAD = "Load a seed" + LOAD = ButtonOption("Load a seed") def __init__(self): super().__init__() @@ -41,8 +42,8 @@ class SeedsMenuView(View): button_data = [] for seed in self.seeds: - button_data.append((seed["fingerprint"], SeedSignerIconConstants.FINGERPRINT)) - button_data.append(_("Load a seed")) + button_data.append(ButtonOption(seed["fingerprint"], SeedSignerIconConstants.FINGERPRINT)) + button_data.append(self.LOAD) selected_menu_num = self.run_screen( ButtonListScreen, @@ -54,7 +55,7 @@ class SeedsMenuView(View): if len(self.seeds) > 0 and selected_menu_num < len(self.seeds): 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) 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. verify single sig addr or sign message). """ - SCAN_SEED = (_("Scan a seed"), SeedSignerIconConstants.QRCODE) - TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) + SCAN_SEED = ButtonOption("Scan a seed", SeedSignerIconConstants.QRCODE) + TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD) + TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD) + TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD) def __init__(self, flow: str = None): @@ -108,11 +109,7 @@ class SeedSelectSeedView(View): button_data = [] for seed in seeds: button_str = seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK)) - - if seed.passphrase is not None: - # TODO: Include lock icon on right side of button - pass - button_data.append((button_str, SeedSignerIconConstants.FINGERPRINT, "blue")) + button_data.append(ButtonOption(button_str, SeedSignerIconConstants.FINGERPRINT, icon_color="blue")) button_data.append(self.SCAN_SEED) button_data.append(self.TYPE_12WORD) @@ -165,11 +162,11 @@ class SeedSelectSeedView(View): Loading seeds, passphrases, etc ****************************************************************************""" class LoadSeedView(View): - SEED_QR = (_("Scan a SeedQR"), SeedSignerIconConstants.QRCODE) - TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) - CREATE = (_(" Create a seed"), SeedSignerIconConstants.PLUS) + SEED_QR = ButtonOption("Scan a SeedQR", SeedSignerIconConstants.QRCODE) + TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD) + TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD) + TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD) + CREATE = ButtonOption(" Create a seed", SeedSignerIconConstants.PLUS) def run(self): button_data = [ @@ -274,8 +271,8 @@ class SeedMnemonicEntryView(View): class SeedMnemonicInvalidView(View): - EDIT = _("Review & Edit") - DISCARD = (_("Discard"), None, None, "red") + EDIT = ButtonOption("Review & Edit") + DISCARD = ButtonOption("Discard", button_label_color="red") def __init__(self): super().__init__() @@ -303,8 +300,8 @@ class SeedMnemonicInvalidView(View): class SeedFinalizeView(View): - FINALIZE = _("Done") - PASSPHRASE = _("BIP-39 Passphrase") + FINALIZE = ButtonOption("Done") + PASSPHRASE = ButtonOption("BIP-39 Passphrase") def __init__(self): super().__init__() @@ -327,9 +324,9 @@ class SeedFinalizeView(View): def run(self): 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: - button_data.append(passphrase_button) + button_data.append(self.PASSPHRASE) selected_menu_num = self.run_screen( seed_screens.SeedFinalizeScreen, @@ -341,7 +338,7 @@ class SeedFinalizeView(View): seed_num = self.controller.storage.finalize_pending_seed() 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) elif selected_menu_num == RET_CODE__BACK_BUTTON: @@ -377,8 +374,8 @@ class SeedAddPassphraseView(View): class SeedAddPassphraseExitDialogView(View): - EDIT = _("Edit passphrase") - DISCARD = (_("Discard passphrase"), None, None, "red") + EDIT = ButtonOption("Edit passphrase") + DISCARD = ButtonOption("Discard passphrase", button_label_color="red") def __init__(self): super().__init__() @@ -410,8 +407,8 @@ class SeedReviewPassphraseView(View): """ Display the completed passphrase back to the user. """ - EDIT = _("Edit passphrase") - DONE = _("Done") + EDIT = ButtonOption("Edit passphrase") + DONE = ButtonOption("Done") def __init__(self): super().__init__() @@ -450,8 +447,8 @@ class SeedReviewPassphraseView(View): class SeedDiscardView(View): - KEEP = _("Keep Seed") - DISCARD = (_("Discard"), None, None, "red") + KEEP = ButtonOption("Keep Seed") + DISCARD = ButtonOption("Discard", button_label_color="red") def __init__(self, seed_num: int = None): super().__init__() @@ -518,14 +515,14 @@ class SeedElectrumMnemonicStartView(View): Views for actions on individual seeds: ****************************************************************************""" class SeedOptionsView(View): - SCAN_PSBT = (_("Scan PSBT"), SeedSignerIconConstants.QRCODE) - VERIFY_ADDRESS = _("Verify Addr") - EXPORT_XPUB = _("Export Xpub") - EXPLORER = _("Address Explorer") - SIGN_MESSAGE = _("Sign Message") - BACKUP = (_("Backup Seed"), None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT) - BIP85_CHILD_SEED = _("BIP-85 Child Seed") - DISCARD = (_("Discard Seed"), None, None, "red") + SCAN_PSBT = ButtonOption("Scan PSBT", SeedSignerIconConstants.QRCODE) + VERIFY_ADDRESS = ButtonOption("Verify Addr") + EXPORT_XPUB = ButtonOption("Export Xpub") + EXPLORER = ButtonOption("Address Explorer") + SIGN_MESSAGE = ButtonOption("Sign Message") + BACKUP = ButtonOption("Backup Seed", right_icon_name=SeedSignerIconConstants.CHEVRON_RIGHT) + BIP85_CHILD_SEED = ButtonOption("BIP-85 Child Seed") + DISCARD = ButtonOption("Discard Seed", button_label_color="red") def __init__(self, seed_num: int): @@ -630,8 +627,8 @@ class SeedOptionsView(View): class SeedBackupView(View): - VIEW_WORDS = _("View Seed Words") - EXPORT_SEEDQR = _("Export as SeedQR") + VIEW_WORDS = ButtonOption("View Seed Words") + EXPORT_SEEDQR = ButtonOption("Export as SeedQR") def __init__(self, seed_num): super().__init__() @@ -667,8 +664,8 @@ class SeedBackupView(View): Export Xpub flow ****************************************************************************""" class SeedExportXpubSigTypeView(View): - SINGLE_SIG = _("Single Sig") - MULTISIG = _("Multisig") + SINGLE_SIG = ButtonOption("Single Sig", return_data=SettingsConstants.SINGLE_SIG) + MULTISIG = ButtonOption("Multisig", return_data=SettingsConstants.MULTISIG) def __init__(self, seed_num: int): super().__init__() @@ -680,7 +677,7 @@ class SeedExportXpubSigTypeView(View): # 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) - button_data=[self.SINGLE_SIG, self.MULTISIG] + button_data = [self.SINGLE_SIG, self.MULTISIG] selected_menu_num = self.run_screen( ButtonListScreen, @@ -691,11 +688,7 @@ class SeedExportXpubSigTypeView(View): if selected_menu_num == RET_CODE__BACK_BUTTON: return Destination(BackStackView) - if button_data[selected_menu_num] == self.SINGLE_SIG: - 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}) + return Destination(SeedExportXpubScriptTypeView, view_args={"seed_num": self.seed_num, "sig_type": button_data[selected_menu_num].return_data}) @@ -737,13 +730,13 @@ class SeedExportXpubScriptTypeView(View): button_data = [] for script_type, display_name in SettingsConstants.ALL_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( ButtonListScreen, title=title, is_button_text_centered=False, - button_data=[x[1] for x in button_data], + button_data=button_data, is_bottom_list=True, ) @@ -754,7 +747,7 @@ class SeedExportXpubScriptTypeView(View): return Destination(BackStackView) 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: return Destination(SeedExportXpubCustomDerivationView, view_args=args) @@ -826,7 +819,9 @@ class SeedExportXpubCoordinatorView(View): args["coordinator"] = self.settings.get_value(SettingsConstants.SETTING__COORDINATORS)[0] 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( ButtonListScreen, @@ -838,9 +833,10 @@ class SeedExportXpubCoordinatorView(View): if selected_menu_num == RET_CODE__BACK_BUTTON: return Destination(BackStackView) - coordinators_settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__COORDINATORS) - selected_display_name = button_data[selected_menu_num] - args["coordinator"] = coordinators_settings_entry.get_selection_option_value_by_display_name(selected_display_name) + # coordinators_settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__COORDINATORS) + # 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"] = button_data[selected_menu_num].return_data return Destination(SeedExportXpubWarningView, view_args=args) @@ -1048,8 +1044,8 @@ class SeedWordsWarningView(View): class SeedWordsView(View): - NEXT = _("Next") - DONE = _("Done") + NEXT = ButtonOption("Next") + DONE = ButtonOption("Done") def __init__(self, seed_num: int, bip85_data: dict = None, page_index: int = 0): super().__init__() @@ -1126,14 +1122,14 @@ class SeedBIP85ApplicationModeView(View): * XPRV (BIP32) """ # TODO: Future enhancement to display WIF (HD-SEED) and XPRV (Bip32)? - WORDS_12 = _("12 Words") - WORDS_24 = _("24 Words") + WORDS_12 = ButtonOption("12 Words") + WORDS_24 = ButtonOption("24 Words") def __init__(self, seed_num: int): super().__init__() self.seed_num = seed_num 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): @@ -1159,8 +1155,8 @@ class SeedBIP85ApplicationModeView(View): -# View to retrieve the derived seed index class SeedBIP85SelectChildIndexView(View): + # View to retrieve the derived seed index def __init__(self, seed_num: int, num_words: int): super().__init__() self.seed_num = seed_num @@ -1168,7 +1164,7 @@ class SeedBIP85SelectChildIndexView(View): 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() if ret == RET_CODE__BACK_BUTTON: @@ -1206,7 +1202,7 @@ class SeedBIP85InvalidChildIndexView(View): show_back_button=False, status_headline=_("Invalid Child Index"), text=_("BIP-85 Child Index must be between 0 and 2^31-1."), - button_data=[_("Try Again")] + button_data=[ButtonOption("Try Again")] ).display() return Destination( @@ -1224,8 +1220,8 @@ class SeedBIP85InvalidChildIndexView(View): Seed Words Backup Test ****************************************************************************""" class SeedWordsBackupTestPromptView(View): - VERIFY = _("Verify") - SKIP = _("Skip") + VERIFY = ButtonOption("Verify") + SKIP = ButtonOption("Skip") def __init__(self, seed_num: int, bip85_data: dict = None): super().__init__() @@ -1283,10 +1279,10 @@ class SeedWordsBackupTestView(View): while self.cur_index in self.confirmed_list: self.cur_index = int(random.random() * len(self.mnemonic_list)) - real_word = self.mnemonic_list[self.cur_index] - fake_word1 = bip39.WORDLIST[int(random.random() * 2047)] - fake_word2 = bip39.WORDLIST[int(random.random() * 2047)] - fake_word3 = bip39.WORDLIST[int(random.random() * 2047)] + real_word = ButtonOption(self.mnemonic_list[self.cur_index]) + fake_word1 = ButtonOption(bip39.WORDLIST[int(random.random() * 2047)]) + fake_word2 = ButtonOption(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] random.shuffle(button_data) @@ -1332,8 +1328,8 @@ class SeedWordsBackupTestView(View): class SeedWordsBackupTestMistakeView(View): - REVIEW = _("Review Seed Words") - RETRY = _("Try Again") + REVIEW = ButtonOption("Review Seed Words") + 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): super().__init__() @@ -1392,7 +1388,7 @@ class SeedWordsBackupTestSuccessView(View): show_back_button=False, status_headline=_("Success!"), text=_("All mnemonic backup words were successfully verified!"), - button_data=[_("OK")] + button_data=[ButtonOption("OK")] ).display() if self.seed_num is not None: @@ -1414,15 +1410,11 @@ class SeedTranscribeSeedQRFormatView(View): def run(self): seed = self.controller.get_seed(self.seed_num) if len(seed.mnemonic_list) == 12: - STANDARD = _("Standard: 25x25") - COMPACT = _("Compact: 21x21") - num_modules_standard = 25 - num_modules_compact = 21 + STANDARD = ButtonOption("Standard: 25x25", return_data=25) + COMPACT = ButtonOption("Compact: 21x21", return_data=21) else: - STANDARD = _("Standard: 29x29") - COMPACT = _("Compact: 25x25") - num_modules_standard = 29 - num_modules_compact = 25 + STANDARD = ButtonOption("Standard: 29x29", return_data=29) + COMPACT = ButtonOption("Compact: 25x25", return_data=25) if self.settings.get_value(SettingsConstants.SETTING__COMPACT_SEEDQR) != SettingsConstants.OPTION__ENABLED: # Only configured for standard SeedQR @@ -1431,7 +1423,7 @@ class SeedTranscribeSeedQRFormatView(View): view_args={ "seed_num": self.seed_num, "seedqr_format": QRType.SEED__SEEDQR, - "num_modules": num_modules_standard, + "num_modules": STANDARD.return_data, }, skip_current_view=True, ) @@ -1450,10 +1442,10 @@ class SeedTranscribeSeedQRFormatView(View): if button_data[selected_menu_num] == STANDARD: seedqr_format = QRType.SEED__SEEDQR - num_modules = num_modules_standard else: seedqr_format = QRType.SEED__COMPACTSEEDQR - num_modules = num_modules_compact + + num_modules = button_data[selected_menu_num].return_data return Destination( SeedTranscribeSeedQRWarningView, @@ -1580,8 +1572,8 @@ class SeedTranscribeSeedQRZoomedInView(View): class SeedTranscribeSeedQRConfirmQRPromptView(View): - SCAN = (_("Confirm SeedQR"), SeedSignerIconConstants.QRCODE) - DONE = _("Done") + SCAN = ButtonOption("Confirm SeedQR", SeedSignerIconConstants.QRCODE) + DONE = ButtonOption("Done") def __init__(self, seed_num: int): super().__init__() @@ -1726,8 +1718,8 @@ class AddressVerificationStartView(View): class AddressVerificationSigTypeView(View): - SINGLE_SIG = _("Single Sig") - MULTISIG = _("Multisig") + SINGLE_SIG = ButtonOption("Single Sig") + MULTISIG = ButtonOption("Multisig") def run(self): from seedsigner.helpers import embit_utils @@ -1781,8 +1773,8 @@ class SeedAddressVerificationView(View): multisig. """ # TRANSLATOR_NOTE: Option when scanning for a matching address; skips ten addresses ahead - SKIP_10 = _("Skip 10") - CANCEL = _("Cancel") + SKIP_10 = ButtonOption("Skip 10") + CANCEL = ButtonOption("Cancel") def __init__(self, seed_num: int = None): super().__init__() @@ -2000,8 +1992,8 @@ class AddressVerificationSuccessView(View): class LoadMultisigWalletDescriptorView(View): - SCAN = (_("Scan Descriptor"), SeedSignerIconConstants.QRCODE) - CANCEL = _("Cancel") + SCAN = ButtonOption("Scan Descriptor", SeedSignerIconConstants.QRCODE) + CANCEL = ButtonOption("Cancel") def run(self): button_data = [self.SCAN, self.CANCEL] @@ -2025,10 +2017,10 @@ class LoadMultisigWalletDescriptorView(View): class MultisigWalletDescriptorView(View): - RETURN = _("Return to PSBT") - VERIFY_ADDR = _("Verify Addr") - ADDRESS_EXPLORER = _("Address Explorer") - OK = _("OK") + RETURN = ButtonOption("Return to PSBT") + VERIFY_ADDR = ButtonOption("Verify Addr") + ADDRESS_EXPLORER = ButtonOption("Address Explorer") + OK = ButtonOption("OK") def run(self): descriptor = self.controller.multisig_wallet_descriptor @@ -2047,8 +2039,8 @@ class MultisigWalletDescriptorView(View): if self.controller.resume_main_flow == Controller.FLOW__PSBT: button_data = [self.RETURN] 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]}""" - button_data = [verify_addr_display] + verify_addr_display = f"""{_(self.VERIFY_ADDR.button_label)} {self.controller.unverified_address["address"][:7]}""" + button_data = [ButtonOption(verify_addr_display)] elif self.controller.resume_main_flow == Controller.FLOW__ADDRESS_EXPLORER: button_data = [self.ADDRESS_EXPLORER] @@ -2069,7 +2061,7 @@ class MultisigWalletDescriptorView(View): self.controller.resume_main_flow = None 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 return Destination(SeedAddressVerificationView) @@ -2111,12 +2103,7 @@ class SeedSignMessageStartView(View): # Note: addr_format["network"] can be MAINNET or [TESTNET, REGTEST] if self.settings.get_value(SettingsConstants.SETTING__NETWORK) not in addr_format["network"]: from seedsigner.views.view import NetworkMismatchErrorView - # TRANSLATOR_NOTE: Inserts mainnet/testnet/regtest and 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))) + self.set_redirect(Destination(NetworkMismatchErrorView, view_args=dict(derivation_path=self.derivation_path))) # 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. @@ -2203,11 +2190,7 @@ class SeedSignMessageConfirmAddressView(View): addr_format["network"] = self.settings.get_value(SettingsConstants.SETTING__NETWORK) else: from seedsigner.views.view import NetworkMismatchErrorView - 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))) + self.set_redirect(Destination(NetworkMismatchErrorView, view_args=dict(derivation_path=self.derivation_path))) # 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. diff --git a/src/seedsigner/views/settings_views.py b/src/seedsigner/views/settings_views.py index a48314cf..b4fb86a6 100644 --- a/src/seedsigner/views/settings_views.py +++ b/src/seedsigner/views/settings_views.py @@ -3,6 +3,7 @@ from gettext import gettext as _ from seedsigner.gui.components import SeedSignerIconConstants 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 .view import View, Destination, MainMenuView @@ -12,8 +13,8 @@ logger = logging.getLogger(__name__) class SettingsMenuView(View): - IO_TEST = _("I/O test") - DONATE = _("Donate") + IO_TEST = ButtonOption("I/O test") + DONATE = ButtonOption("Donate") def __init__(self, visibility: str = SettingsConstants.VISIBILITY__GENERAL, selected_attr: str = None, initial_scroll: int = 0): super().__init__() @@ -28,7 +29,7 @@ class SettingsMenuView(View): settings_entries = SettingsDefinition.get_settings_entries( 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 if self.selected_attr: @@ -41,7 +42,7 @@ class SettingsMenuView(View): title = _("Settings") # 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}) button_data.append(self.IO_TEST) @@ -114,7 +115,7 @@ class SettingsEntryUpdateSelectionView(View): value, display_name = value else: 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: checked_buttons.append(i) @@ -211,7 +212,6 @@ class SettingsIngestSettingsQRView(View): SettingsQRConfirmationScreen, title=_("Settings QR"), config_name=self.config_name, - button_data=[_("Home")], status_message=self.status_message, ) diff --git a/src/seedsigner/views/tools_views.py b/src/seedsigner/views/tools_views.py index fd94dfc2..acfdd377 100644 --- a/src/seedsigner/views/tools_views.py +++ b/src/seedsigner/views/tools_views.py @@ -7,6 +7,7 @@ from gettext import gettext as _ from seedsigner.gui.components import FontAwesomeIconConstants, GUIConstants, SeedSignerIconConstants 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.models.seed import Seed from seedsigner.models.settings_definition import SettingsConstants @@ -19,11 +20,11 @@ logger = logging.getLogger(__name__) class ToolsMenuView(View): - IMAGE = (_("New seed"), FontAwesomeIconConstants.CAMERA) - DICE = (_("New seed"), FontAwesomeIconConstants.DICE) - KEYBOARD = (_("Calc 12th/24th word"), FontAwesomeIconConstants.KEYBOARD) - ADDRESS_EXPLORER = _("Address Explorer") - VERIFY_ADDRESS = _("Verify Address") + IMAGE = ButtonOption("New seed", FontAwesomeIconConstants.CAMERA) + DICE = ButtonOption("New seed", FontAwesomeIconConstants.DICE) + KEYBOARD = ButtonOption("Calc 12th/24th word", FontAwesomeIconConstants.KEYBOARD) + ADDRESS_EXPLORER = ButtonOption("Address Explorer") + VERIFY_ADDRESS = ButtonOption("Verify Address") def run(self): button_data = [self.IMAGE, self.DICE, self.KEYBOARD, self.ADDRESS_EXPLORER, self.VERIFY_ADDRESS] @@ -113,8 +114,8 @@ class ToolsImageEntropyFinalImageView(View): class ToolsImageEntropyMnemonicLengthView(View): - TWELVE_WORDS = _("12 words") - TWENTYFOUR_WORDS = _("24 words") + TWELVE_WORDS = ButtonOption("12 words", return_data=12) + TWENTYFOUR_WORDS = ButtonOption("24 words", return_data=24) def run(self): button_data = [self.TWELVE_WORDS, self.TWENTYFOUR_WORDS] @@ -127,10 +128,7 @@ class ToolsImageEntropyMnemonicLengthView(View): if selected_menu_num == RET_CODE__BACK_BUTTON: return Destination(BackStackView) - if button_data[selected_menu_num] == self.TWELVE_WORDS: - mnemonic_length = 12 - else: - mnemonic_length = 24 + mnemonic_length = button_data[selected_menu_num].return_data preview_images = self.controller.image_entropy_preview_frames seed_entropy_image = self.controller.image_entropy_final_image @@ -186,15 +184,19 @@ class ToolsImageEntropyMnemonicLengthView(View): Dice rolls Views ****************************************************************************""" 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): - 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( title=_("Mnemonic Length"), is_bottom_list=True, @@ -205,10 +207,10 @@ class ToolsDiceEntropyMnemonicLengthView(View): if selected_menu_num == RET_CODE__BACK_BUTTON: 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)) - 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)) @@ -243,8 +245,8 @@ class ToolsDiceEntropyEntryView(View): Calc final word Views ****************************************************************************""" class ToolsCalcFinalWordNumWordsView(View): - TWELVE = _("12 words") - TWENTY_FOUR = _("24 words") + TWELVE = ButtonOption("12 words", return_data=12) + TWENTY_FOUR = ButtonOption("24 words", return_data=24) def run(self): button_data = [self.TWELVE, self.TWENTY_FOUR] @@ -260,29 +262,21 @@ class ToolsCalcFinalWordNumWordsView(View): if selected_menu_num == RET_CODE__BACK_BUTTON: return Destination(BackStackView) - elif button_data[selected_menu_num] == self.TWELVE: - self.controller.storage.init_pending_mnemonic(12) + self.controller.storage.init_pending_mnemonic(button_data[selected_menu_num].return_data) - # 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)) + return Destination(SeedMnemonicEntryView, view_args=dict(is_calc_final_word=True)) class ToolsCalcFinalWordFinalizePromptView(View): # 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 - SELECT_WORD = _("Word selection entropy") + SELECT_WORD = ButtonOption("Word selection entropy") # TRANSLATOR_NOTE: Label to allow user to default entropy as all-zeros - ZEROS = _("Finalize with zeros") + ZEROS = ButtonOption("Finalize with zeros") def run(self): from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordFinalizePromptScreen @@ -343,7 +337,7 @@ class ToolsCalcFinalWordCoinFlipsView(View): class ToolsCalcFinalWordShowFinalWordView(View): - NEXT = _("Next") + NEXT = ButtonOption("Next") def __init__(self, coin_flips: str = None): super().__init__() @@ -399,10 +393,13 @@ class ToolsCalcFinalWordShowFinalWordView(View): def run(self): from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordScreen 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( ToolsCalcFinalWordScreen, - # TRANSLATOR_NOTE: label to calculate the last word of a BIP-39 mnemonic seed phrase - title=_("Final Word Calc"), + title=title, button_data=button_data, selected_final_word=self.selected_final_word, selected_final_bits=self.selected_final_bits, @@ -419,8 +416,8 @@ class ToolsCalcFinalWordShowFinalWordView(View): class ToolsCalcFinalWordDoneView(View): - LOAD = _("Load seed") - DISCARD = (_("Discard"), None, None, "red") + LOAD = ButtonOption("Load seed") + DISCARD = ButtonOption("Discard", button_label_color="red") def run(self): from seedsigner.gui.screens.tools_screens import ToolsCalcFinalWordDoneScreen @@ -454,11 +451,11 @@ class ToolsCalcFinalWordDoneView(View): Address Explorer Views ****************************************************************************""" class ToolsAddressExplorerSelectSourceView(View): - SCAN_SEED = (_("Scan a seed"), SeedSignerIconConstants.QRCODE) - SCAN_DESCRIPTOR = (_("Scan wallet descriptor"), SeedSignerIconConstants.QRCODE) - TYPE_12WORD = (_("Enter 12-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_24WORD = (_("Enter 24-word seed"), FontAwesomeIconConstants.KEYBOARD) - TYPE_ELECTRUM = (_("Enter Electrum seed"), FontAwesomeIconConstants.KEYBOARD) + SCAN_SEED = ButtonOption("Scan a seed", SeedSignerIconConstants.QRCODE) + SCAN_DESCRIPTOR = ButtonOption("Scan wallet descriptor", SeedSignerIconConstants.QRCODE) + TYPE_12WORD = ButtonOption("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD, return_data=12) + TYPE_24WORD = ButtonOption("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD, return_data=24) + TYPE_ELECTRUM = ButtonOption("Enter Electrum seed", FontAwesomeIconConstants.KEYBOARD) def run(self): from seedsigner.controller import Controller @@ -467,11 +464,11 @@ class ToolsAddressExplorerSelectSourceView(View): button_data = [] for seed in seeds: 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] if self.settings.get_value(SettingsConstants.SETTING__ELECTRUM_SEEDS) == SettingsConstants.OPTION__ENABLED: button_data.append(self.TYPE_ELECTRUM) - + selected_menu_num = self.run_screen( ButtonListScreen, title=_("Address Explorer"), @@ -508,10 +505,7 @@ class ToolsAddressExplorerSelectSourceView(View): elif button_data[selected_menu_num] in [self.TYPE_12WORD, self.TYPE_24WORD]: from seedsigner.views.seed_views import SeedMnemonicEntryView - if button_data[selected_menu_num] == self.TYPE_12WORD: - self.controller.storage.init_pending_mnemonic(num_words=12) - else: - self.controller.storage.init_pending_mnemonic(num_words=24) + self.controller.storage.init_pending_mnemonic(num_words=button_data[selected_menu_num].return_data) return Destination(SeedMnemonicEntryView) elif button_data[selected_menu_num] == self.TYPE_ELECTRUM: @@ -522,10 +516,10 @@ class ToolsAddressExplorerSelectSourceView(View): class ToolsAddressExplorerAddressTypeView(View): # 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 - CHANGE = _("Change Addresses") + CHANGE = ButtonOption("Change Addresses") 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 else: 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") - 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( ButtonListScreen, diff --git a/src/seedsigner/views/view.py b/src/seedsigner/views/view.py index 0f157db9..9472068e 100644 --- a/src/seedsigner/views/view.py +++ b/src/seedsigner/views/view.py @@ -1,10 +1,11 @@ -from dataclasses import dataclass, field +from dataclasses import dataclass from gettext import gettext as _ 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.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_definition import SettingsDefinition from seedsigner.models.threads import BaseThread @@ -18,6 +19,7 @@ class BackStackView: pass + """ 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 @@ -182,14 +184,13 @@ class Destination: # ######################################################################################### class MainMenuView(View): - SCAN = (_("Scan"), SeedSignerIconConstants.SCAN) - SEEDS = (_("Seeds"), SeedSignerIconConstants.SEEDS) - TOOLS = (_("Tools"), SeedSignerIconConstants.TOOLS) - SETTINGS = (_("Settings"), SeedSignerIconConstants.SETTINGS) + SCAN = ButtonOption("Scan", SeedSignerIconConstants.SCAN) + SEEDS = ButtonOption("Seeds", SeedSignerIconConstants.SEEDS) + TOOLS = ButtonOption("Tools", SeedSignerIconConstants.TOOLS) + SETTINGS = ButtonOption("Settings", SeedSignerIconConstants.SETTINGS) def run(self): from seedsigner.gui.screens.screen import MainMenuScreen - button_data = [self.SCAN, self.SEEDS, self.TOOLS, self.SETTINGS] selected_menu_num = self.run_screen( MainMenuScreen, @@ -219,8 +220,8 @@ class MainMenuView(View): class PowerOptionsView(View): - RESET = (_("Restart"), SeedSignerIconConstants.RESTART) - POWER_OFF = (_("Power Off"), SeedSignerIconConstants.POWER) + RESET = ButtonOption("Restart", SeedSignerIconConstants.RESTART) + POWER_OFF = ButtonOption("Power Off", SeedSignerIconConstants.POWER) def run(self): button_data = [self.RESET, self.POWER_OFF] @@ -293,12 +294,7 @@ class NotYetImplementedView(View): """ Temporary View to use during dev. """ - text: str = None - - def __post_init__(self): - if not self.text: - self.text = _("This is still on our to-do list!") - return super().__post_init__() + text: str = _mft("This is still on our to-do list!") def run(self): @@ -307,7 +303,7 @@ class NotYetImplementedView(View): title=_("Work In Progress"), status_headline=_("Not Yet Implemented"), text=self.text, - button_data=[_("Back to Main Menu")], + button_data=[ButtonOption("Back to Main Menu")], ) return Destination(MainMenuView) @@ -316,13 +312,12 @@ class NotYetImplementedView(View): @dataclass class ErrorView(View): - title: str = _("Error") + title: str = _mft("Error") show_back_button: bool = True status_headline: str = None 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): self.run_screen( @@ -330,33 +325,30 @@ class ErrorView(View): title=self.title, status_headline=self.status_headline, text=self.text, - button_data=[self.button_text], + button_data=[ButtonOption(self.button_text)], show_back_button=self.show_back_button, ) - - return self.next_destination + return self.next_destination if self.next_destination else Destination(MainMenuView, clear_history=True) @dataclass class NetworkMismatchErrorView(ErrorView): - title: str = _("Network Mismatch") - show_back_button: bool = False - button_text: str = _("Change Setting") - next_destination: Destination = None - + derivation_path: str = None 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__() - 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: - from seedsigner.views.settings_views import SettingsEntryUpdateSelectionView - self.next_destination = Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=SettingsConstants.SETTING__NETWORK), clear_history=True) + # TRANSLATOR_NOTE: Inserts mainnet/testnet/regtest and derivation path + self.text = _("Current network setting ({}) doesn't match {}.").format( + self.settings.get_value_display_name(SettingsConstants.SETTING__NETWORK), + self.derivation_path, + ) @@ -380,14 +372,12 @@ class UnhandledExceptionView(View): @dataclass class OptionDisabledView(View): - UPDATE_SETTING = "Update Setting" - DONE = "Done" + UPDATE_SETTING = ButtonOption("Update Setting") + DONE = ButtonOption("Done") settings_attr: str def __post_init__(self): super().__post_init__() - self.UPDATE_SETTING = _("Update Setting") - self.DONE = _("Done") 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...) @@ -413,26 +403,3 @@ class OptionDisabledView(View): return Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=self.settings_attr), clear_history=True) else: 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) diff --git a/tests/screenshot_generator/generator.py b/tests/screenshot_generator/generator.py index 90b40da9..68bfd8eb 100644 --- a/tests/screenshot_generator/generator.py +++ b/tests/screenshot_generator/generator.py @@ -295,7 +295,7 @@ def test_generate_screenshots(target_locale): "Misc Error Views": [ NotYetImplementedView, (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)), (ErrorView, dict( title="Error", diff --git a/tests/test_flows_psbt.py b/tests/test_flows_psbt.py index 964b0d67..b8661800 100644 --- a/tests/test_flows_psbt.py +++ b/tests/test_flows_psbt.py @@ -115,7 +115,7 @@ class TestPSBTFlows(FlowTest): 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(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.SeedReviewPassphraseView, button_data_selection=seed_views.SeedReviewPassphraseView.DONE), FlowStep(seed_views.SeedOptionsView, is_redirect=True), diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index f6ef501d..490e9f15 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -5,7 +5,7 @@ import pytest from base import BaseTest, FlowTest, FlowStep 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.seed import ElectrumSeed, Seed from seedsigner.views.view import ErrorView, MainMenuView, OptionDisabledView, View, NetworkMismatchErrorView @@ -40,10 +40,10 @@ class TestSeedFlows(FlowTest): self.run_sequence([ FlowStep(MainMenuView, button_data_selection=MainMenuView.SCAN), FlowStep(scan_views.ScanView, before_run=load_seed_into_decoder), # simulate read SeedQR; ret val is ignored - FlowStep(seed_views.SeedFinalizeView, button_data_selection=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.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.SeedAddPassphraseExitDialogView, button_data_selection=seed_views.SeedAddPassphraseExitDialogView.EDIT), 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 """ - 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( initial_destination_view_args=dict(seed_num=0), sequence=[ 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.SeedExportXpubScriptTypeView, button_data_selection=script_tuple[1]), - FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=coord_tuple[1]), + FlowStep(seed_views.SeedExportXpubSigTypeView, button_data_selection=sig_selection), + FlowStep(seed_views.SeedExportXpubScriptTypeView, button_data_selection=ButtonOption(script_tuple[1], return_data=script_tuple[0])), + 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.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), @@ -303,10 +306,18 @@ class TestSeedFlows(FlowTest): SettingsConstants.CUSTOM_DERIVATION ]) - # get display names to access button choices in the views (ugh: hardcoding, is there a better way?) - sig_type = self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__SIG_TYPES)[0] # single sig - 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 + # Ensure that all coordinators are enabled + self.settings.set_value(SettingsConstants.SETTING__COORDINATORS, [x for x, y in SettingsConstants.ALL_COORDINATORS]) + + # 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( initial_destination_view_args=dict(seed_num=0), @@ -377,7 +388,7 @@ class TestSeedFlows(FlowTest): # Skips past the script type options via redirect 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.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), diff --git a/tests/test_flows_settings.py b/tests/test_flows_settings.py index c449f679..37adf006 100644 --- a/tests/test_flows_settings.py +++ b/tests/test_flows_settings.py @@ -8,7 +8,7 @@ from base import FlowTest, FlowStep from seedsigner.models.settings import Settings 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.views.view import MainMenuView from seedsigner.views import scan_views, settings_views @@ -26,8 +26,8 @@ class TestSettingsFlows(FlowTest): self.run_sequence([ FlowStep(MainMenuView, button_data_selection=MainMenuView.SETTINGS), - FlowStep(settings_views.SettingsMenuView, button_data_selection=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.SettingsMenuView, button_data_selection=ButtonOption(settings_entry.display_name)), + 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.SettingsMenuView), ]) @@ -43,7 +43,7 @@ class TestSettingsFlows(FlowTest): self.run_sequence([ 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=1), # select/deselect second option FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=1), # select/deselect second option diff --git a/tests/test_flows_tools.py b/tests/test_flows_tools.py index 588859be..c803765d 100644 --- a/tests/test_flows_tools.py +++ b/tests/test_flows_tools.py @@ -2,7 +2,7 @@ from base import FlowTest, FlowStep 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.settings_definition import SettingsConstants, SettingsDefinition from seedsigner.views.view import ErrorView, MainMenuView @@ -25,7 +25,7 @@ class TestToolsFlows(FlowTest): FlowStep(MainMenuView, button_data_selection=MainMenuView.TOOLS), 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(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.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 @@ -62,7 +62,7 @@ class TestToolsFlows(FlowTest): # Finalize the new seed w/passphrase self.run_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.SeedReviewPassphraseView, button_data_selection=seed_views.SeedReviewPassphraseView.DONE), FlowStep(seed_views.SeedOptionsView, is_redirect=True),