diff --git a/src/seedsigner/gui/components.py b/src/seedsigner/gui/components.py index 6414b71a..6c0f68ae 100644 --- a/src/seedsigner/gui/components.py +++ b/src/seedsigner/gui/components.py @@ -217,9 +217,9 @@ class SeedSignerIconConstants: # Messaging icons INFO = "\ue912" - ERROR = "\ue913" - SUCCESS = "\ue914" - WARNING = "\ue915" + SUCCESS = "\ue913" + WARNING = "\ue914" + ERROR = "\ue915" # Informational icons ADDRESS = "\ue916" @@ -241,8 +241,9 @@ class SeedSignerIconConstants: DELETE = "\ue922" SPACE = "\ue923" + # Must be updated whenever new icons are added. See usage in `Icon` class below. MIN_VALUE = SCAN - MAX_VALUE = QRCODE + MAX_VALUE = SPACE @@ -280,17 +281,6 @@ def calc_text_centering(font: ImageFont, -def load_icon(icon_name: str, load_selected_variant: bool = False): - icon_url = os.path.join(pathlib.Path(__file__).parent.resolve(), "..", "resources", "icons", icon_name) - icon = Image.open(icon_url + ".png").convert("RGB") - if not load_selected_variant: - return icon - else: - icon_selected = Image.open(icon_url + "_selected.png").convert("RGB") - return (icon, icon_selected) - - - def load_image(image_name: str) -> Image.Image: image_url = os.path.join(pathlib.Path(__file__).parent.resolve(), "..", "resources", "img", image_name) image = Image.open(image_url).convert("RGB") diff --git a/src/seedsigner/gui/keyboard.py b/src/seedsigner/gui/keyboard.py index 0ccc91e9..bc679ec5 100644 --- a/src/seedsigner/gui/keyboard.py +++ b/src/seedsigner/gui/keyboard.py @@ -71,14 +71,14 @@ class Keyboard: } KEY_CURSOR_LEFT = { "code": "CURSOR_LEFT", - "letter": "<", - "font": REGULAR_KEY_FONT, + "letter": SeedSignerIconConstants.CHEVRON_LEFT, + "font": ICON_KEY_FONT, "size": 1, } KEY_CURSOR_RIGHT = { "code": "CURSOR_RIGHT", - "letter": ">", - "font": REGULAR_KEY_FONT, + "letter": SeedSignerIconConstants.CHEVRON_RIGHT, + "font": ICON_KEY_FONT, "size": 1, } KEY_PREVIOUS_PAGE = { diff --git a/src/seedsigner/gui/screens/screen.py b/src/seedsigner/gui/screens/screen.py index 637b00a9..aa50f88e 100644 --- a/src/seedsigner/gui/screens/screen.py +++ b/src/seedsigner/gui/screens/screen.py @@ -309,7 +309,7 @@ class ButtonListScreen(BaseTopNavScreen): if len(self.button_data) == 1: button_list_height = button_height else: - button_list_height = (len(self.button_data) * button_height) + (GUIConstants.COMPONENT_PADDING * (len(self.button_data) - 1)) + button_list_height = (len(self.button_data) * button_height) + (GUIConstants.LIST_ITEM_PADDING * (len(self.button_data) - 1)) if self.is_bottom_list: button_list_y = self.canvas_height - (button_list_height + GUIConstants.EDGE_PADDING) diff --git a/src/seedsigner/gui/screens/settings_screens.py b/src/seedsigner/gui/screens/settings_screens.py index 794e5b2e..c41eadfc 100644 --- a/src/seedsigner/gui/screens/settings_screens.py +++ b/src/seedsigner/gui/screens/settings_screens.py @@ -6,7 +6,7 @@ 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.components import Button, CheckboxButton, CheckedSelectionButton, FontAwesomeIconConstants, Fonts, GUIConstants, Icon, IconButton, IconTextLine, SeedSignerIconConstants, TextArea from seedsigner.gui.screens.scan_screens import ScanScreen from seedsigner.gui.screens.screen import BaseScreen, BaseTopNavScreen, ButtonListScreen, ButtonOption from seedsigner.hardware.buttons import HardwareButtonsConstants @@ -82,7 +82,7 @@ class IOTestScreen(BaseTopNavScreen): self.components.append(self.joystick_click_button) self.joystick_up_button = IconButton( - icon_name=FontAwesomeIconConstants.ANGLE_UP, + icon_name=SeedSignerIconConstants.CHEVRON_UP, icon_size=GUIConstants.ICON_INLINE_FONT_SIZE, width=input_button_width, height=input_button_height, @@ -93,7 +93,7 @@ class IOTestScreen(BaseTopNavScreen): self.components.append(self.joystick_up_button) self.joystick_down_button = IconButton( - icon_name=FontAwesomeIconConstants.ANGLE_DOWN, + icon_name=SeedSignerIconConstants.CHEVRON_DOWN, icon_size=GUIConstants.ICON_INLINE_FONT_SIZE, width=input_button_width, height=input_button_height, @@ -104,9 +104,8 @@ class IOTestScreen(BaseTopNavScreen): self.components.append(self.joystick_down_button) self.joystick_left_button = IconButton( - text=FontAwesomeIconConstants.ANGLE_LEFT, - font_name=GUIConstants.ICON_FONT_NAME__FONT_AWESOME, - font_size=GUIConstants.ICON_INLINE_FONT_SIZE, + icon_name=SeedSignerIconConstants.CHEVRON_LEFT, + icon_size=GUIConstants.ICON_INLINE_FONT_SIZE, width=input_button_width, height=input_button_height, screen_x=dpad_center_x - input_button_width - GUIConstants.COMPONENT_PADDING, @@ -116,7 +115,7 @@ class IOTestScreen(BaseTopNavScreen): self.components.append(self.joystick_left_button) self.joystick_right_button = IconButton( - icon_name=FontAwesomeIconConstants.ANGLE_RIGHT, + icon_name=SeedSignerIconConstants.CHEVRON_RIGHT, icon_size=GUIConstants.ICON_INLINE_FONT_SIZE, width=input_button_width, height=input_button_height, diff --git a/src/seedsigner/gui/screens/tools_screens.py b/src/seedsigner/gui/screens/tools_screens.py index c99c2b7a..0b291c01 100644 --- a/src/seedsigner/gui/screens/tools_screens.py +++ b/src/seedsigner/gui/screens/tools_screens.py @@ -140,7 +140,7 @@ class ToolsDiceEntropyEntryScreen(KeyboardScreen): self.rows = 3 self.cols = 3 self.keyboard_font_name = GUIConstants.ICON_FONT_NAME__FONT_AWESOME - self.keyboard_font_size = None # Force auto-scaling to Key height + self.keyboard_font_size = 36 self.keys_charset = "".join([ FontAwesomeIconConstants.DICE_ONE, FontAwesomeIconConstants.DICE_TWO, diff --git a/src/seedsigner/views/psbt_views.py b/src/seedsigner/views/psbt_views.py index 636751d1..b4caf938 100644 --- a/src/seedsigner/views/psbt_views.py +++ b/src/seedsigner/views/psbt_views.py @@ -460,17 +460,16 @@ class PSBTAddressVerificationFailedView(View): def run(self): if self.is_multisig: - title = _("Caution") # TRANSLATOR_NOTE: Variable is either "change" or "self-transfer". - text = _("PSBT's {} address could not be verified with your multisig wallet descriptor.").format(_("change") if self.is_change else _("self-transfer")) + text = _("PSBT's {} address could not be verified from wallet descriptor.").format(_("change") if self.is_change else _("self-transfer")) else: - title = _("Suspicious PSBT") # TRANSLATOR_NOTE: Variable is either "change" or "self-transfer". text = _("PSBT's {} address could not be generated from your seed.").format(_("change") if self.is_change else _("self-transfer")) DireWarningScreen( - title=title, + title=_("Suspicious PSBT"), status_headline=_("Address Verification Failed"), + status_icon_name=SeedSignerIconConstants.ERROR, text=text, button_data=[ButtonOption("Discard PSBT")], show_back_button=False, diff --git a/src/seedsigner/views/scan_views.py b/src/seedsigner/views/scan_views.py index aa83c6bd..dc7d828b 100644 --- a/src/seedsigner/views/scan_views.py +++ b/src/seedsigner/views/scan_views.py @@ -2,6 +2,7 @@ import logging import re from gettext import gettext as _ +from seedsigner.gui.components import SeedSignerIconConstants 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 @@ -163,8 +164,13 @@ class ScanView(View): # For now, don't even try to re-do the attempted operation, just reset and # start everything over. self.controller.resume_main_flow = None + + # TODO: Refactor this warning screen into its own Screen class; the + # screenshot generator is currently manually re-creating it, but it would be + # better if a dedicated Screen could just be instantiated instead. return Destination(ErrorView, view_args=dict( title=_("Error"), + status_icon_name=SeedSignerIconConstants.WARNING, status_headline=_("Unknown QR Type"), text=_("QRCode is invalid or is a data format not yet supported."), button_text=_("Done"), diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index 7a9c5121..ae369587 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -279,8 +279,9 @@ class SeedMnemonicInvalidView(View): def run(self): button_data = [self.EDIT, self.DISCARD] selected_menu_num = self.run_screen( - WarningScreen, + DireWarningScreen, title=_("Invalid Mnemonic!"), + status_icon_name=SeedSignerIconConstants.ERROR, status_headline=None, text=_("Checksum failure; not a valid seed phrase."), show_back_button=False, @@ -1206,6 +1207,7 @@ class SeedBIP85InvalidChildIndexView(View): DireWarningScreen( title=_("BIP-85 Index Error"), show_back_button=False, + status_icon_name=SeedSignerIconConstants.ERROR, status_headline=_("Invalid Child Index"), text=_("BIP-85 Child Index must be between 0 and 2^31-1."), button_data=[ButtonOption("Try Again")] @@ -1366,6 +1368,7 @@ class SeedWordsBackupTestMistakeView(View): selected_menu_num = DireWarningScreen( title=_("Verification Error"), show_back_button=False, + status_icon_name=SeedSignerIconConstants.ERROR, status_headline=status_headline, button_data=button_data, text=text, diff --git a/src/seedsigner/views/view.py b/src/seedsigner/views/view.py index e7673eef..62811458 100644 --- a/src/seedsigner/views/view.py +++ b/src/seedsigner/views/view.py @@ -300,6 +300,7 @@ class NotYetImplementedView(View): class ErrorView(View): title: str = _mft("Error") show_back_button: bool = True + status_icon_name: str = SeedSignerIconConstants.ERROR status_headline: str = None text: str = None button_text: str = None @@ -309,6 +310,7 @@ class ErrorView(View): self.run_screen( WarningScreen, title=self.title, + status_icon_name=self.status_icon_name, status_headline=self.status_headline, text=self.text, button_data=[ButtonOption(self.button_text)], @@ -324,9 +326,14 @@ class NetworkMismatchErrorView(ErrorView): 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") + + # TRANSLATOR_NOTE: The network setting (mainnet/testnet/regtest) doesn't match the provided derivation path + self.title = _("Network Mismatch") + self.status_icon_name = SeedSignerIconConstants.WARNING + self.show_back_button = False + + # TRANSLATOR_NOTE: Button option to alter a setting + self.button_text = _("Change Setting") self.next_destination = Destination(SettingsEntryUpdateSelectionView, view_args=dict(attr_name=SettingsConstants.SETTING__NETWORK), clear_history=True) super().__post_init__() @@ -347,6 +354,7 @@ class UnhandledExceptionView(View): self.run_screen( DireWarningScreen, title=_("System Error"), + status_icon_name=SeedSignerIconConstants.ERROR, status_headline=self.error[0], text=self.error[1] + "\n" + self.error[2], allow_text_overflow=True, # Fit what we can, let the rest go off the edges diff --git a/tests/screenshot_generator/generator.py b/tests/screenshot_generator/generator.py index 114f5c68..c82ae5ad 100644 --- a/tests/screenshot_generator/generator.py +++ b/tests/screenshot_generator/generator.py @@ -24,6 +24,7 @@ sys.modules['seedsigner.hardware.microsd'] = MagicMock() patch('PIL.ImageFont.core.HAVE_RAQM', False).start() from seedsigner.controller import Controller +from seedsigner.gui.components import SeedSignerIconConstants from seedsigner.gui.renderer import Renderer from seedsigner.gui.screens.seed_screens import SeedAddPassphraseScreen from seedsigner.gui.toast import BaseToastOverlayManagerThread, RemoveSDCardToastManagerThread, SDCardStateChangeToastManagerThread @@ -359,12 +360,17 @@ def generate_screenshots(locale): ScreenshotConfig(UnhandledExceptionView, dict(error=["IndexError", "line 1, in some_buggy_code.py", "list index out of range"])), ScreenshotConfig(NetworkMismatchErrorView, dict(derivation_path="m/84'/1'/0'")), ScreenshotConfig(OptionDisabledView, dict(settings_attr=SettingsConstants.SETTING__MESSAGE_SIGNING)), - ScreenshotConfig(ErrorView, dict( - title="Error", - status_headline="Unknown QR Type", - text="QRCode is invalid or is a data format not yet supported.", - button_text="Back", - )), + ScreenshotConfig( + ErrorView, + dict( + title="Error", + status_icon_name=SeedSignerIconConstants.WARNING, + status_headline="Unknown QR Type", + text="QRCode is invalid or is a data format not yet supported.", + button_text="Back", + ), + screenshot_name="ScanView__UnknownQRType" + ), ] }