mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 15:08:25 +00:00
Icon font update
- Renamed `seedsigner-glyphs.otf` to `seedsigner-icons.otf` - Updated `seedsigner-icons.otf` - Renamed `SeedSignerCustomIconConstants` to `SeedSignerIconConstants` - Updated `SeedSignerCustomIconConstants` names and Unicode values in src/seedsigner/gui/components.py
This commit is contained in:
@@ -28,7 +28,7 @@ class GUIConstants:
|
||||
REGTEST_COLOR = "#00caf1"
|
||||
|
||||
ICON_FONT_NAME__FONT_AWESOME = "Font_Awesome_6_Free-Solid-900"
|
||||
ICON_FONT_NAME__SEEDSIGNER = "seedsigner-glyphs"
|
||||
ICON_FONT_NAME__SEEDSIGNER = "seedsigner-icons"
|
||||
ICON_FONT_SIZE = 22
|
||||
ICON_INLINE_FONT_SIZE = 24
|
||||
ICON_LARGE_BUTTON_SIZE = 36
|
||||
@@ -69,10 +69,6 @@ class FontAwesomeIconConstants:
|
||||
ANGLE_RIGHT = "\uf105"
|
||||
ANGLE_UP = "\uf106"
|
||||
CAMERA = "\uf030"
|
||||
CARET_DOWN = "\uf0d7"
|
||||
CARET_LEFT = "\uf0d9"
|
||||
CARET_RIGHT = "\uf0da"
|
||||
CARET_UP = "\uf0d8"
|
||||
CHEVRON_UP = "\uf077"
|
||||
CHEVRON_DOWN = "\uf078"
|
||||
SOLID_CIRCLE_CHECK = "\uf058"
|
||||
@@ -85,46 +81,59 @@ class FontAwesomeIconConstants:
|
||||
DICE_FOUR = "\uf524"
|
||||
DICE_FIVE = "\uf523"
|
||||
DICE_SIX = "\uf526"
|
||||
GEAR = "\uf013"
|
||||
KEY = "\uf084"
|
||||
KEYBOARD = "\uf11c"
|
||||
LOCK = "\uf023"
|
||||
MAP = "\uf279"
|
||||
PAPER_PLANE = "\uf1d8"
|
||||
PEN = "\uf304"
|
||||
PLUS = "+"
|
||||
POWER_OFF = "\uf011"
|
||||
ROTATE_RIGHT = "\uf2f9"
|
||||
SCREWDRIVER_WRENCH = "\uf7d9"
|
||||
SDCARD = "\uf7c2"
|
||||
SQUARE = "\uf0c8"
|
||||
SQUARE_CARET_DOWN = "\uf150"
|
||||
SQUARE_CARET_LEFT = "\uf191"
|
||||
SQUARE_CARET_RIGHT = "\uf152"
|
||||
SQUARE_CARET_UP = "\uf151"
|
||||
SQUARE_CHECK = "\uf14a"
|
||||
TRIANGLE_EXCLAMATION = "\uf071"
|
||||
UNLOCK = "\uf09c"
|
||||
QRCODE = "\uf029"
|
||||
X = "\u0058"
|
||||
SDCARD = "\uf7c2"
|
||||
|
||||
|
||||
class SeedSignerCustomIconConstants:
|
||||
LARGE_CHEVRON_LEFT = "\ue900"
|
||||
SMALL_CHEVRON_RIGHT = "\ue901"
|
||||
PAGE_UP = "\ue903"
|
||||
PAGE_DOWN = "\ue902"
|
||||
PLUS = "\ue904"
|
||||
CIRCLE_CHECK = "\ue907"
|
||||
CIRCLE_EXCLAMATION = "\ue908"
|
||||
CIRCLE_X = "\ue909"
|
||||
FINGERPRINT = "\ue90a"
|
||||
PATH = "\ue90b"
|
||||
BITCOIN_LOGO_STRAIGHT = "\ue90c"
|
||||
BITCOIN_LOGO_TILTED = "\ue90d"
|
||||
class SeedSignerIconConstants:
|
||||
SCAN = "\ue900"
|
||||
SEEDS = "\ue901"
|
||||
SETTINGS = "\ue902"
|
||||
TOOLS = "\ue903"
|
||||
|
||||
MIN_VALUE = LARGE_CHEVRON_LEFT
|
||||
MAX_VALUE = BITCOIN_LOGO_TILTED
|
||||
BACK = "\ue904"
|
||||
CHEVRON_DOWN = "\ue905"
|
||||
CHEVRON_LEFT = "\ue906"
|
||||
CHEVRON_RIGHT = "\ue907"
|
||||
CHEVRON_UP = "\ue908"
|
||||
CLOSE = "\ue909"
|
||||
PAGE_DOWN = "\ue90a"
|
||||
PAGE_UP = "\ue90b"
|
||||
PLUS = "\ue90c"
|
||||
POWER = "\ue90d"
|
||||
|
||||
ERROR = "\ue90e"
|
||||
SUCCESS = "\ue90f"
|
||||
WARNING = "\ue910"
|
||||
|
||||
ADDRESS = "\ue911"
|
||||
CHANGE = "\ue912"
|
||||
DERIVATION = "\ue913"
|
||||
FEE = "\ue914"
|
||||
FINGERPRINT = "\ue915"
|
||||
PASSPHRASE = "\ue916"
|
||||
|
||||
BITCOIN = "\ue917"
|
||||
BITCOIN_ALT = "\ue918"
|
||||
BRIGHTNESS = "\ue919"
|
||||
MICROSD = "\ue91a"
|
||||
QRCODE = "\ue91b"
|
||||
|
||||
MIN_VALUE = BACK
|
||||
MAX_VALUE = BITCOIN_ALT
|
||||
|
||||
|
||||
|
||||
@@ -425,7 +434,7 @@ class TextArea(BaseComponent):
|
||||
class Icon(BaseComponent):
|
||||
screen_x: int = 0
|
||||
screen_y: int = 0
|
||||
icon_name: str = SeedSignerCustomIconConstants.BITCOIN_LOGO_TILTED
|
||||
icon_name: str = SeedSignerIconConstants.BITCOIN_ALT
|
||||
icon_size: int = GUIConstants.ICON_FONT_SIZE
|
||||
icon_color: str = GUIConstants.BODY_FONT_COLOR
|
||||
|
||||
@@ -859,7 +868,7 @@ class BtcAmount(BaseComponent):
|
||||
btc_icon = Icon(
|
||||
image_draw=draw,
|
||||
canvas=self.paste_image,
|
||||
icon_name=SeedSignerCustomIconConstants.BITCOIN_LOGO_TILTED,
|
||||
icon_name=SeedSignerIconConstants.BITCOIN_ALT,
|
||||
icon_color=btc_color,
|
||||
icon_size=self.icon_size,
|
||||
screen_x=0,
|
||||
@@ -947,7 +956,7 @@ class BtcAmount(BaseComponent):
|
||||
btc_icon = Icon(
|
||||
image_draw=draw,
|
||||
canvas=self.paste_image,
|
||||
icon_name=SeedSignerCustomIconConstants.BITCOIN_LOGO_TILTED,
|
||||
icon_name=SeedSignerIconConstants.BITCOIN_ALT,
|
||||
icon_color=btc_color,
|
||||
icon_size=self.icon_size,
|
||||
screen_x=0,
|
||||
@@ -1279,7 +1288,7 @@ class TopNav(BaseComponent):
|
||||
|
||||
if self.show_back_button:
|
||||
self.left_button = IconButton(
|
||||
icon_name=SeedSignerCustomIconConstants.LARGE_CHEVRON_LEFT,
|
||||
icon_name=SeedSignerIconConstants.BACK,
|
||||
icon_size=GUIConstants.ICON_INLINE_FONT_SIZE,
|
||||
screen_x=GUIConstants.EDGE_PADDING,
|
||||
screen_y=GUIConstants.EDGE_PADDING,
|
||||
@@ -1289,7 +1298,7 @@ class TopNav(BaseComponent):
|
||||
|
||||
if self.show_power_button:
|
||||
self.right_button = IconButton(
|
||||
icon_name=FontAwesomeIconConstants.POWER_OFF,
|
||||
icon_name=SeedSignerIconConstants.POWER,
|
||||
icon_size=GUIConstants.ICON_INLINE_FONT_SIZE,
|
||||
screen_x=self.width - GUIConstants.TOP_NAV_BUTTON_SIZE - GUIConstants.EDGE_PADDING,
|
||||
screen_y=GUIConstants.EDGE_PADDING,
|
||||
|
||||
@@ -655,7 +655,7 @@ class PSBTChangeDetailsScreen(ButtonListScreen):
|
||||
# Adjust the vertical spacing
|
||||
screen_y -= GUIConstants.COMPONENT_PADDING
|
||||
self.components.append(IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.FINGERPRINT,
|
||||
icon_name=SeedSignerIconConstants.FINGERPRINT,
|
||||
icon_color="blue",
|
||||
value_text=f"""{"Multisig" if self.is_multisig else self.fingerprint}: {"Change" if self.is_change_derivation_path else "Addr"} #{self.derivation_path_addr_index}""",
|
||||
is_text_centered=False,
|
||||
@@ -665,7 +665,7 @@ class PSBTChangeDetailsScreen(ButtonListScreen):
|
||||
|
||||
if self.is_change_addr_verified:
|
||||
self.components.append(IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.CIRCLE_CHECK,
|
||||
icon_name=SeedSignerIconConstants.SUCCESS,
|
||||
icon_color="#00dd00",
|
||||
value_text="Address verified!",
|
||||
is_text_centered=False,
|
||||
|
||||
@@ -692,7 +692,7 @@ class QRDisplayScreen(BaseScreen):
|
||||
canvas=rectangle,
|
||||
screen_x=GUIConstants.EDGE_PADDING*2 + 1,
|
||||
screen_y=GUIConstants.COMPONENT_PADDING + 4, # +4 fudge factor to account for where the chevron is drawn relative to baseline
|
||||
icon_name=FontAwesomeIconConstants.CHEVRON_UP,
|
||||
icon_name=SeedSignerIconConstants.CHEVRON_UP,
|
||||
icon_size=GUIConstants.BODY_FONT_SIZE,
|
||||
)
|
||||
chevron_up_icon.render()
|
||||
@@ -702,7 +702,7 @@ class QRDisplayScreen(BaseScreen):
|
||||
canvas=rectangle,
|
||||
screen_x=chevron_up_icon.screen_x,
|
||||
screen_y=chevron_up_icon.screen_y + chevron_up_icon.icon_size + GUIConstants.BODY_LINE_SPACING,
|
||||
icon_name=FontAwesomeIconConstants.CHEVRON_DOWN,
|
||||
icon_name=SeedSignerIconConstants.CHEVRON_DOWN,
|
||||
icon_size=chevron_up_icon.icon_size,
|
||||
)
|
||||
chevron_down_icon.render()
|
||||
@@ -824,7 +824,7 @@ class QRDisplayScreen(BaseScreen):
|
||||
@dataclass
|
||||
class LargeIconStatusScreen(ButtonListScreen):
|
||||
title: str = "Success!"
|
||||
status_icon_name: str = SeedSignerCustomIconConstants.CIRCLE_CHECK
|
||||
status_icon_name: str = SeedSignerIconConstants.SUCCESS
|
||||
status_icon_size: int = GUIConstants.ICON_PRIMARY_SCREEN_SIZE
|
||||
status_color: str = GUIConstants.SUCCESS_COLOR
|
||||
status_headline: str = "Success!" # The colored text under the large icon
|
||||
@@ -948,7 +948,7 @@ class WarningEdgesMixin:
|
||||
@dataclass
|
||||
class WarningScreen(WarningEdgesMixin, LargeIconStatusScreen):
|
||||
title: str = "Caution"
|
||||
status_icon_name: str = SeedSignerCustomIconConstants.CIRCLE_EXCLAMATION
|
||||
status_icon_name: str = SeedSignerIconConstants.WARNING
|
||||
status_color: str = "yellow"
|
||||
status_headline: str = "Privacy Leak!" # The colored text under the alert icon
|
||||
|
||||
@@ -1242,7 +1242,7 @@ class MicroSDToastScreen(BaseScreen):
|
||||
if self.action == MicroSD.ACTION__REMOVED:
|
||||
|
||||
self.toast = ToastOverlay(
|
||||
icon_name=FontAwesomeIconConstants.SDCARD,
|
||||
icon_name=SeedSignerIconConstants.MICROSD,
|
||||
color=GUIConstants.NOTIFICATION_COLOR,
|
||||
label_text="MicroSD removed"
|
||||
)
|
||||
@@ -1250,7 +1250,7 @@ class MicroSDToastScreen(BaseScreen):
|
||||
elif self.action == MicroSD.ACTION__INSERTED:
|
||||
|
||||
self.toast = ToastOverlay(
|
||||
icon_name=FontAwesomeIconConstants.SDCARD,
|
||||
icon_name=SeedSignerIconConstants.MICROSD,
|
||||
color=GUIConstants.NOTIFICATION_COLOR,
|
||||
label_text="MicroSD inserted"
|
||||
)
|
||||
|
||||
@@ -421,7 +421,7 @@ class SeedFinalizeScreen(ButtonListScreen):
|
||||
super().__post_init__()
|
||||
|
||||
self.fingerprint_icontl = IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.FINGERPRINT,
|
||||
icon_name=SeedSignerIconConstants.FINGERPRINT,
|
||||
icon_color="blue",
|
||||
icon_size=GUIConstants.ICON_FONT_SIZE + 12,
|
||||
label_text="fingerprint",
|
||||
@@ -441,7 +441,7 @@ class SeedOptionsScreen(ButtonListScreen):
|
||||
has_passphrase: bool = False
|
||||
|
||||
def __post_init__(self):
|
||||
self.top_nav_icon_name = SeedSignerCustomIconConstants.FINGERPRINT
|
||||
self.top_nav_icon_name = SeedSignerIconConstants.FINGERPRINT
|
||||
self.top_nav_icon_color = "blue"
|
||||
self.title = self.fingerprint
|
||||
self.is_button_text_centered = False
|
||||
@@ -584,7 +584,7 @@ class SeedExportXpubDetailsScreen(WarningEdgesMixin, ButtonListScreen):
|
||||
|
||||
# Set up the fingerprint and passphrase displays
|
||||
self.fingerprint_line = IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.FINGERPRINT,
|
||||
icon_name=SeedSignerIconConstants.FINGERPRINT,
|
||||
icon_color="blue",
|
||||
label_text="Fingerprint",
|
||||
value_text=self.fingerprint,
|
||||
@@ -594,7 +594,7 @@ class SeedExportXpubDetailsScreen(WarningEdgesMixin, ButtonListScreen):
|
||||
self.components.append(self.fingerprint_line)
|
||||
|
||||
self.derivation_line = IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.PATH,
|
||||
icon_name=SeedSignerIconConstants.DERIVATION,
|
||||
label_text="Derivation",
|
||||
value_text=self.derivation_path,
|
||||
screen_x=GUIConstants.COMPONENT_PADDING,
|
||||
@@ -1009,7 +1009,7 @@ class SeedReviewPassphraseScreen(ButtonListScreen):
|
||||
super().__post_init__()
|
||||
|
||||
self.components.append(IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.FINGERPRINT,
|
||||
icon_name=SeedSignerIconConstants.FINGERPRINT,
|
||||
icon_color="blue",
|
||||
label_text="changes fingerprint",
|
||||
value_text=f"{self.fingerprint_without} >> {self.fingerprint_with}",
|
||||
|
||||
@@ -362,7 +362,7 @@ class ToolsCalcFinalWordDoneScreen(ButtonListScreen):
|
||||
))
|
||||
|
||||
self.components.append(IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.FINGERPRINT,
|
||||
icon_name=SeedSignerIconConstants.FINGERPRINT,
|
||||
icon_color="blue",
|
||||
label_text="fingerprint",
|
||||
value_text=self.fingerprint,
|
||||
@@ -386,7 +386,7 @@ class ToolsAddressExplorerAddressTypeScreen(ButtonListScreen):
|
||||
|
||||
if self.fingerprint:
|
||||
self.components.append(IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.FINGERPRINT,
|
||||
icon_name=SeedSignerIconConstants.FINGERPRINT,
|
||||
icon_color="blue",
|
||||
label_text="Fingerprint",
|
||||
value_text=self.fingerprint,
|
||||
@@ -396,7 +396,7 @@ class ToolsAddressExplorerAddressTypeScreen(ButtonListScreen):
|
||||
|
||||
if self.script_type != SettingsConstants.CUSTOM_DERIVATION:
|
||||
self.components.append(IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.PATH,
|
||||
icon_name=SeedSignerIconConstants.DERIVATION,
|
||||
label_text="Derivation",
|
||||
value_text=SettingsDefinition.get_settings_entry(attr_name=SettingsConstants.SETTING__SCRIPT_TYPES).get_selection_option_display_name_by_value(value=self.script_type),
|
||||
screen_x=GUIConstants.EDGE_PADDING,
|
||||
@@ -404,7 +404,7 @@ class ToolsAddressExplorerAddressTypeScreen(ButtonListScreen):
|
||||
))
|
||||
else:
|
||||
self.components.append(IconTextLine(
|
||||
icon_name=SeedSignerCustomIconConstants.PATH,
|
||||
icon_name=SeedSignerIconConstants.DERIVATION,
|
||||
label_text="Derivation",
|
||||
value_text=self.custom_derivation_path,
|
||||
screen_x=GUIConstants.EDGE_PADDING,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -21,7 +21,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PSBTSelectSeedView(View):
|
||||
SCAN_SEED = ("Scan a seed", FontAwesomeIconConstants.QRCODE)
|
||||
SCAN_SEED = ("Scan a seed", SeedSignerIconConstants.QRCODE)
|
||||
TYPE_12WORD = ("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
TYPE_24WORD = ("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
button_data = []
|
||||
@@ -41,7 +41,7 @@ class PSBTSelectSeedView(View):
|
||||
# Doesn't look like this seed can sign the current PSBT
|
||||
button_str += " (?)"
|
||||
|
||||
self.button_data.append((button_str, SeedSignerCustomIconConstants.FINGERPRINT, "blue"))
|
||||
self.button_data.append((button_str, SeedSignerIconConstants.FINGERPRINT, "blue"))
|
||||
|
||||
self.button_data.append(self.SCAN_SEED)
|
||||
self.button_data.append(self.TYPE_12WORD)
|
||||
@@ -531,7 +531,7 @@ class PSBTSigningErrorView(View):
|
||||
# Just a WarningScreen here; only use DireWarningScreen for true security risks.
|
||||
selected_menu_num = WarningScreen(
|
||||
title="PSBT Error",
|
||||
status_icon_name=SeedSignerCustomIconConstants.CIRCLE_EXCLAMATION,
|
||||
status_icon_name=SeedSignerIconConstants.WARNING,
|
||||
status_headline="Signing Failed",
|
||||
text="Signing with this seed did not add a valid signature.",
|
||||
button_data=["Select Diff Seed"],
|
||||
|
||||
@@ -49,7 +49,7 @@ class SeedsMenuView(View):
|
||||
|
||||
button_data = []
|
||||
for seed in self.seeds:
|
||||
button_data.append((seed["fingerprint"], SeedSignerCustomIconConstants.FINGERPRINT, "blue"))
|
||||
button_data.append((seed["fingerprint"], SeedSignerIconConstants.FINGERPRINT, "blue"))
|
||||
button_data.append("Load a seed")
|
||||
|
||||
selected_menu_num = self.run_screen(
|
||||
@@ -74,10 +74,10 @@ class SeedsMenuView(View):
|
||||
Loading seeds, passphrases, etc
|
||||
****************************************************************************"""
|
||||
class LoadSeedView(View):
|
||||
SEED_QR = (" Scan a SeedQR", FontAwesomeIconConstants.QRCODE)
|
||||
SEED_QR = (" Scan a SeedQR", SeedSignerIconConstants.QRCODE)
|
||||
TYPE_12WORD = ("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
TYPE_24WORD = ("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
CREATE = (" Create a seed", FontAwesomeIconConstants.PLUS)
|
||||
CREATE = (" Create a seed", SeedSignerIconConstants.PLUS)
|
||||
|
||||
def run(self):
|
||||
button_data = [
|
||||
@@ -340,11 +340,11 @@ class SeedDiscardView(View):
|
||||
Views for actions on individual seeds:
|
||||
****************************************************************************"""
|
||||
class SeedOptionsView(View):
|
||||
SCAN_PSBT = ("Scan PSBT", FontAwesomeIconConstants.QRCODE)
|
||||
SCAN_PSBT = ("Scan PSBT", SeedSignerIconConstants.QRCODE)
|
||||
VERIFY_ADDRESS = "Verify Addr"
|
||||
EXPORT_XPUB = "Export Xpub"
|
||||
EXPLORER = "Address Explorer"
|
||||
BACKUP = ("Backup Seed", None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT)
|
||||
BACKUP = ("Backup Seed", None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT)
|
||||
BIP85_CHILD_SEED = "BIP-85 Child Seed"
|
||||
DISCARD = ("Discard Seed", None, None, "red")
|
||||
|
||||
@@ -1354,7 +1354,7 @@ class SeedTranscribeSeedQRConfirmQRPromptView(View):
|
||||
|
||||
|
||||
def run(self):
|
||||
SCAN = ("Confirm SeedQR", FontAwesomeIconConstants.QRCODE)
|
||||
SCAN = ("Confirm SeedQR", SeedSignerIconConstants.QRCODE)
|
||||
DONE = "Done"
|
||||
button_data = [SCAN, DONE]
|
||||
|
||||
@@ -1529,7 +1529,7 @@ class SeedSingleSigAddressVerificationSelectSeedView(View):
|
||||
def run(self):
|
||||
seeds = self.controller.storage.seeds
|
||||
|
||||
SCAN_SEED = ("Scan a seed", FontAwesomeIconConstants.QRCODE)
|
||||
SCAN_SEED = ("Scan a seed", SeedSignerIconConstants.QRCODE)
|
||||
TYPE_12WORD = ("Enter 12-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
TYPE_24WORD = ("Enter 24-word seed", FontAwesomeIconConstants.KEYBOARD)
|
||||
button_data = []
|
||||
@@ -1538,7 +1538,7 @@ class SeedSingleSigAddressVerificationSelectSeedView(View):
|
||||
|
||||
for seed in seeds:
|
||||
button_str = seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK))
|
||||
button_data.append((button_str, SeedSignerCustomIconConstants.FINGERPRINT, "blue"))
|
||||
button_data.append((button_str, SeedSignerIconConstants.FINGERPRINT, "blue"))
|
||||
text = "Select seed to verify"
|
||||
|
||||
button_data.append(SCAN_SEED)
|
||||
@@ -1784,7 +1784,7 @@ class AddressVerificationSuccessView(View):
|
||||
|
||||
class LoadMultisigWalletDescriptorView(View):
|
||||
def run(self):
|
||||
SCAN = ("Scan Descriptor", FontAwesomeIconConstants.QRCODE)
|
||||
SCAN = ("Scan Descriptor", SeedSignerIconConstants.QRCODE)
|
||||
CANCEL = "Cancel"
|
||||
button_data = [SCAN, CANCEL]
|
||||
selected_menu_num = seed_screens.LoadMultisigWalletDescriptorScreen(
|
||||
|
||||
@@ -40,7 +40,7 @@ class SettingsMenuView(View):
|
||||
title = "Settings"
|
||||
|
||||
# Set up the next nested level of menuing
|
||||
button_data.append(("Advanced", None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT))
|
||||
button_data.append(("Advanced", None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT))
|
||||
next_destination = Destination(SettingsMenuView, view_args={"visibility": SettingsConstants.VISIBILITY__ADVANCED})
|
||||
|
||||
button_data.append(self.IO_TEST)
|
||||
@@ -50,7 +50,7 @@ class SettingsMenuView(View):
|
||||
title = "Advanced"
|
||||
|
||||
# So far there are no real Developer options; disabling for now
|
||||
# button_data.append(("Developer Options", None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT))
|
||||
# button_data.append(("Developer Options", None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT))
|
||||
# next_destination = Destination(SettingsMenuView, view_args={"visibility": SettingsConstants.VISIBILITY__DEVELOPER})
|
||||
next_destination = None
|
||||
|
||||
|
||||
@@ -425,8 +425,8 @@ class ToolsCalcFinalWordDoneView(View):
|
||||
Address Explorer Views
|
||||
****************************************************************************"""
|
||||
class ToolsAddressExplorerSelectSourceView(View):
|
||||
SCAN_SEED = ("Scan a seed", FontAwesomeIconConstants.QRCODE)
|
||||
SCAN_DESCRIPTOR = ("Scan wallet descriptor", FontAwesomeIconConstants.QRCODE)
|
||||
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)
|
||||
|
||||
@@ -436,7 +436,7 @@ 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, SeedSignerCustomIconConstants.FINGERPRINT, "blue"))
|
||||
button_data.append((button_str, SeedSignerIconConstants.FINGERPRINT, "blue"))
|
||||
button_data = button_data + [self.SCAN_SEED, self.SCAN_DESCRIPTOR, self.TYPE_12WORD, self.TYPE_24WORD]
|
||||
|
||||
selected_menu_num = self.run_screen(
|
||||
@@ -630,7 +630,7 @@ class ToolsAddressExplorerAddressListView(View):
|
||||
end_digits = -4
|
||||
button_data.append(f"{cur_index}:{address[:8]}...{address[end_digits:]}")
|
||||
|
||||
button_data.append(("Next {}".format(addrs_per_screen), None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT))
|
||||
button_data.append(("Next {}".format(addrs_per_screen), None, None, None, SeedSignerIconConstants.CHEVRON_RIGHT))
|
||||
|
||||
selected_menu_num = self.run_screen(
|
||||
ButtonListScreen,
|
||||
|
||||
@@ -137,10 +137,10 @@ class Destination:
|
||||
#
|
||||
#########################################################################################
|
||||
class MainMenuView(View):
|
||||
SCAN = ("Scan", FontAwesomeIconConstants.QRCODE)
|
||||
SEEDS = ("Seeds", FontAwesomeIconConstants.KEY)
|
||||
TOOLS = ("Tools", FontAwesomeIconConstants.SCREWDRIVER_WRENCH)
|
||||
SETTINGS = ("Settings", FontAwesomeIconConstants.GEAR)
|
||||
SCAN = ("Scan", SeedSignerIconConstants.SCAN)
|
||||
SEEDS = ("Seeds", SeedSignerIconConstants.SEEDS)
|
||||
TOOLS = ("Tools", SeedSignerIconConstants.TOOLS)
|
||||
SETTINGS = ("Settings", SeedSignerIconConstants.SETTINGS)
|
||||
|
||||
def run(self):
|
||||
button_data = [self.SCAN, self.SEEDS, self.TOOLS, self.SETTINGS]
|
||||
@@ -176,7 +176,7 @@ class MainMenuView(View):
|
||||
|
||||
class PowerOptionsView(View):
|
||||
RESET = ("Restart", FontAwesomeIconConstants.ROTATE_RIGHT)
|
||||
POWER_OFF = ("Power Off", FontAwesomeIconConstants.POWER_OFF)
|
||||
POWER_OFF = ("Power Off", SeedSignerIconConstants.POWER)
|
||||
|
||||
def run(self):
|
||||
button_data = [self.RESET, self.POWER_OFF]
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Screenshot Generator
|
||||
|
||||
From the project root, run:
|
||||
```
|
||||
pytest tests/screenshot_generator/generator.py --locale en
|
||||
```
|
||||
|
||||
By default it writes the screenshots to a dir that's parallel to the project root: `seedsigner-screenshots/<locale>`.
|
||||
@@ -0,0 +1,11 @@
|
||||
import pytest
|
||||
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--locale", action="store", default=None)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def target_locale(request):
|
||||
return request.config.option.locale
|
||||
@@ -0,0 +1,221 @@
|
||||
import embit
|
||||
import os
|
||||
import pathlib
|
||||
import pytest
|
||||
from mock import Mock, patch
|
||||
|
||||
from seedsigner.controller import Controller
|
||||
from seedsigner.gui.renderer import Renderer
|
||||
from seedsigner.hardware.buttons import HardwareButtons
|
||||
from seedsigner.hardware.camera import Camera
|
||||
from seedsigner.models.decode_qr import DecodeQR
|
||||
from seedsigner.models.qr_type import QRType
|
||||
from seedsigner.models.seed import Seed
|
||||
from seedsigner.models.settings import Settings
|
||||
from seedsigner.models.settings_definition import SettingsConstants, SettingsDefinition
|
||||
from seedsigner.views import (main_menu_views, psbt_views, scan_views, seed_views,
|
||||
settings_views, tools_views)
|
||||
from seedsigner.views.view import View
|
||||
|
||||
from .utils import ScreenshotComplete, ScreenshotRenderer
|
||||
|
||||
|
||||
|
||||
def test_generate_screenshots(target_locale):
|
||||
"""
|
||||
The `Renderer` class is mocked so that calls in the normal code are ignored
|
||||
(necessary to avoid having it trying to wire up hardware dependencies).
|
||||
|
||||
When the `Renderer` instance is needed, we patch in our own test-only
|
||||
`ScreenshotRenderer`.
|
||||
"""
|
||||
# Disable hardware dependencies by essentially wiping out this class
|
||||
HardwareButtons.get_instance = Mock()
|
||||
Camera.get_instance = Mock()
|
||||
|
||||
# Prep the ScreenshotRenderer that will be patched over the normal Renderer
|
||||
screenshot_root = "/Users/kdmukai/dev/seedsigner-screenshots"
|
||||
ScreenshotRenderer.configure_instance()
|
||||
screenshot_renderer: ScreenshotRenderer = ScreenshotRenderer.get_instance()
|
||||
|
||||
# Replace the core `Singleton` calls so that only our ScreenshotRenderer is used.
|
||||
Renderer.configure_instance = Mock()
|
||||
Renderer.get_instance = Mock(return_value=screenshot_renderer)
|
||||
|
||||
controller = Controller.get_instance()
|
||||
|
||||
# Set up some test data that we'll need in the `Controller` for certain Views
|
||||
mnemonic_12 = "forum undo fragile fade shy sign arrest garment culture tube off merit".split()
|
||||
mnemonic_24 = "attack pizza motion avocado network gather crop fresh patrol unusual wild holiday candy pony ranch winter theme error hybrid van cereal salon goddess expire".split()
|
||||
mnemonic_12b = ["abandon"] * 11 + ["about"]
|
||||
seed_12 = Seed(mnemonic=mnemonic_12, passphrase="cap*BRACKET3stove", wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
|
||||
seed_12b = Seed(mnemonic=mnemonic_12b, wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
|
||||
seed_24 = Seed(mnemonic=mnemonic_24, passphrase="some-PASS*phrase9", wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
|
||||
controller.storage.seeds.append(seed_12)
|
||||
controller.storage.seeds.append(seed_12b)
|
||||
controller.storage.set_pending_seed(seed_24)
|
||||
|
||||
# Load a PSBT into memory
|
||||
BASE64_PSBT_1 = """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"""
|
||||
decoder = DecodeQR()
|
||||
decoder.add_data(BASE64_PSBT_1)
|
||||
controller.psbt = decoder.get_psbt()
|
||||
controller.psbt_seed = seed_12b
|
||||
|
||||
# Multisig wallet descriptor for the multisig in the above PSBT
|
||||
MULTISIG_WALLET_DESCRIPTOR = """wsh(sortedmulti(1,[22bde1a9/48h/1h/0h/2h]tpubDFfsBrmpj226ZYiRszYi2qK6iGvh2vkkghfGB2YiRUVY4rqqedHCFEgw12FwDkm7rUoVtq9wLTKc6BN2sxswvQeQgp7m8st4FP8WtP8go76/{0,1}/*,[73c5da0a/48h/1h/0h/2h]tpubDFH9dgzveyD8zTbPUFuLrGmCydNvxehyNdUXKJAQN8x4aZ4j6UZqGfnqFrD4NqyaTVGKbvEW54tsvPTK2UoSbCC1PJY8iCNiwTL3RWZEheQ/{0,1}/*))#3jhtf6yx"""
|
||||
controller.multisig_wallet_descriptor = embit.descriptor.Descriptor.from_string(MULTISIG_WALLET_DESCRIPTOR)
|
||||
|
||||
# Parse the main `babel/messages.pot` for overall stats
|
||||
messages_source_path = os.path.join(pathlib.Path(__file__).parent.resolve().parent.resolve().parent.resolve(), "babel", "messages.pot")
|
||||
with open(messages_source_path, 'r') as messages_source_file:
|
||||
num_source_messages = messages_source_file.read().count("msgid \"") - 1
|
||||
|
||||
def screencap_view(view_cls: View, view_name: str, view_args: dict={}):
|
||||
screenshot_renderer.set_screenshot_filename(f"{view_name}.png")
|
||||
try:
|
||||
print(f"Running {view_name}")
|
||||
view_cls(**view_args).run()
|
||||
except ScreenshotComplete:
|
||||
# Slightly hacky way to exit ScreenshotRenderer as expected
|
||||
pass
|
||||
print(f"Completed {view_name}")
|
||||
except Exception as e:
|
||||
# Something else went wrong
|
||||
print(repr(e))
|
||||
raise e
|
||||
|
||||
# Automatically populate all Settings options Views
|
||||
settings_views_list = []
|
||||
settings_views_list.append(settings_views.SettingsMenuView)
|
||||
for settings_entry in SettingsDefinition.settings_entries:
|
||||
if settings_entry.visibility == SettingsConstants.VISIBILITY__HIDDEN:
|
||||
continue
|
||||
settings_views_list.append((settings_views.SettingsEntryUpdateSelectionView, dict(attr_name=settings_entry.attr_name), f"SettingsEntryUpdateSelectionView_{settings_entry.attr_name}"))
|
||||
settings_views_list.append(settings_views.IOTestView)
|
||||
settings_views_list.append(settings_views.DonateView)
|
||||
|
||||
|
||||
screenshot_sections = {
|
||||
"Main Menu Views": [
|
||||
main_menu_views.MainMenuView,
|
||||
main_menu_views.PowerOffView,
|
||||
(scan_views.SettingsUpdatedView, dict(config_name="Keith's Settings")),
|
||||
],
|
||||
"Seed Views": [
|
||||
seed_views.SeedsMenuView,
|
||||
seed_views.LoadSeedView,
|
||||
seed_views.SeedMnemonicEntryView,
|
||||
seed_views.SeedMnemonicInvalidView,
|
||||
seed_views.SeedFinalizeView,
|
||||
seed_views.SeedPassphraseWarningView,
|
||||
seed_views.SeedAddPassphraseView,
|
||||
seed_views.SeedReviewPassphraseView,
|
||||
(seed_views.SeedOptionsView, dict(seed_num=0)),
|
||||
(seed_views.SeedBackupView, dict(seed_num=0)),
|
||||
(seed_views.SeedWordsWarningView, dict(seed_num=0)),
|
||||
(seed_views.SeedWordsView, dict(seed_num=0)),
|
||||
(seed_views.SeedWordsView, dict(seed_num=0, page_index=2), "SeedWordsView_2"),
|
||||
(seed_views.SeedTranscribeSeedQRFormatView, dict(seed_num=0)),
|
||||
(seed_views.SeedTranscribeSeedQRWarningView, dict(seed_num=0)),
|
||||
(seed_views.SeedTranscribeSeedQRWholeQRView, dict(seed_num=0, seedqr_format=QRType.SEED__SEEDQR, num_modules=25), "SeedTranscribeSeedQRWholeQRView_12_Standard"),
|
||||
(seed_views.SeedTranscribeSeedQRWholeQRView, dict(seed_num=0, seedqr_format=QRType.SEED__COMPACTSEEDQR, num_modules=21), "SeedTranscribeSeedQRWholeQRView_12_Compact"),
|
||||
|
||||
# Screenshot doesn't render properly due to how the transparency mask is pre-rendered
|
||||
# (seed_views.SeedTranscribeSeedQRZoomedInView, dict(seed_num=0, seedqr_format=QRType.SEED__SEEDQR)),
|
||||
|
||||
(seed_views.SeedTranscribeSeedQRConfirmQRPromptView, dict(seed_num=0)),
|
||||
|
||||
# Screenshot can't render live preview screens
|
||||
# (seed_views.SeedTranscribeSeedQRConfirmScanView, dict(seed_num=0)),
|
||||
|
||||
seed_views.LoadMultisigWalletDescriptorView,
|
||||
seed_views.MultisigWalletDescriptorView,
|
||||
],
|
||||
"PSBT Views": [
|
||||
psbt_views.PSBTSelectSeedView,
|
||||
psbt_views.PSBTOverviewView,
|
||||
psbt_views.PSBTUnsupportedScriptTypeWarningView,
|
||||
psbt_views.PSBTNoChangeWarningView,
|
||||
psbt_views.PSBTMathView,
|
||||
(psbt_views.PSBTAddressDetailsView, dict(address_num=0)),
|
||||
|
||||
# TODO: Render Multisig change w/ and w/out the multisig wallet descriptor onboard
|
||||
(psbt_views.PSBTChangeDetailsView, dict(change_address_num=0)),
|
||||
(psbt_views.PSBTAddressVerificationFailedView, dict(is_change=True, is_multisig=False), "PSBTAddressVerificationFailedView_singlesig_change"),
|
||||
(psbt_views.PSBTAddressVerificationFailedView, dict(is_change=False, is_multisig=False), "PSBTAddressVerificationFailedView_singlesig_selftransfer"),
|
||||
(psbt_views.PSBTAddressVerificationFailedView, dict(is_change=True, is_multisig=True), "PSBTAddressVerificationFailedView_multisig_change"),
|
||||
(psbt_views.PSBTAddressVerificationFailedView, dict(is_change=False, is_multisig=True), "PSBTAddressVerificationFailedView_multisig_selftransfer"),
|
||||
psbt_views.PSBTFinalizeView,
|
||||
psbt_views.PSBTSelectCoordinatorView,
|
||||
psbt_views.PSBTSigningErrorView,
|
||||
],
|
||||
"Tools Views": [
|
||||
tools_views.ToolsMenuView,
|
||||
tools_views.ToolsDiceEntropyMnemonicLengthView,
|
||||
(tools_views.ToolsDiceEntropyEntryView, dict(total_rolls=50)),
|
||||
],
|
||||
"Settings Views": settings_views_list,
|
||||
}
|
||||
|
||||
|
||||
locales = []
|
||||
if target_locale is None:
|
||||
locales = SettingsConstants.ALL_LOCALES
|
||||
else:
|
||||
locales = [locale_tuple for locale_tuple in SettingsConstants.ALL_LOCALES if locale_tuple[0] == target_locale]
|
||||
|
||||
if not locales:
|
||||
raise Exception(f"Invalid locale: {target_locale}")
|
||||
|
||||
for locale, display_name in locales:
|
||||
Settings.get_instance().set_value(SettingsConstants.SETTING__LOCALE, value=locale)
|
||||
screenshot_renderer.set_screenshot_path(os.path.join(screenshot_root, locale))
|
||||
|
||||
locale_readme = f"""# SeedSigner Screenshots: {display_name}\n"""
|
||||
|
||||
# Report the translation progress
|
||||
if locale != SettingsConstants.LOCALE__ENGLISH:
|
||||
translated_messages_path = os.path.join(pathlib.Path(__file__).parent.resolve().parent.resolve().parent.resolve(), "src", "seedsigner", "resources", "babel", locale, "LC_MESSAGES", "messages.po")
|
||||
with open(translated_messages_path, 'r') as translation_file:
|
||||
locale_translations = translation_file.read()
|
||||
num_locale_translations = locale_translations.count("msgid \"") - locale_translations.count("""msgstr ""\n\n""") - 1
|
||||
|
||||
locale_readme += f"## Translation progress: {num_locale_translations / num_source_messages:.1%}\n\n"
|
||||
locale_readme += "---\n\n"
|
||||
|
||||
for section_name, screenshot_list in screenshot_sections.items():
|
||||
locale_readme += "\n\n---\n\n"
|
||||
locale_readme += f"## {section_name}\n\n"
|
||||
locale_readme += """<table style="border: 0;">"""
|
||||
locale_readme += f"""<tr><td align="center">"""
|
||||
for screenshot in screenshot_list:
|
||||
if type(screenshot) == tuple:
|
||||
if len(screenshot) == 2:
|
||||
view_cls, view_args = screenshot
|
||||
view_name = view_cls.__name__
|
||||
elif len(screenshot) == 3:
|
||||
view_cls, view_args, view_name = screenshot
|
||||
else:
|
||||
view_cls = screenshot
|
||||
view_args = {}
|
||||
view_name = view_cls.__name__
|
||||
|
||||
screencap_view(view_cls, view_name, view_args)
|
||||
locale_readme += """<table align="left" style="border: 1px solid gray;">"""
|
||||
locale_readme += f"""<tr><td align="center">{view_name}<br/><br/><img src="{view_name}.png"></td></tr>"""
|
||||
locale_readme += """</table>"""
|
||||
|
||||
locale_readme += "</td></tr></table>"
|
||||
|
||||
with open(os.path.join(screenshot_renderer.screenshot_path, "README.md"), 'w') as readme_file:
|
||||
readme_file.write(locale_readme)
|
||||
|
||||
# Write the main README; ensure it writes all locales, not just the one that may
|
||||
# have been specified for this run.
|
||||
main_readme = """# SeedSigner Screenshots \n\n"""
|
||||
for locale, display_name in SettingsConstants.ALL_LOCALES:
|
||||
main_readme += f"* [{display_name}]({locale}/README.md)\n"
|
||||
|
||||
with open(os.path.join(screenshot_root, "README.md"), 'w') as readme_file:
|
||||
readme_file.write(main_readme)
|
||||
@@ -0,0 +1,53 @@
|
||||
import os
|
||||
from PIL import Image, ImageDraw
|
||||
from seedsigner.gui.renderer import Renderer
|
||||
|
||||
|
||||
class ScreenshotComplete(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ScreenshotRenderer(Renderer):
|
||||
screenshot_path: str = None
|
||||
screenshot_filename: str = None
|
||||
|
||||
@classmethod
|
||||
def configure_instance(cls):
|
||||
# Instantiate the one and only Renderer instance
|
||||
renderer = cls.__new__(cls)
|
||||
cls._instance = renderer
|
||||
|
||||
# Hard-coding output values for now
|
||||
renderer.canvas_width = 240
|
||||
renderer.canvas_height = 240
|
||||
|
||||
renderer.canvas = Image.new('RGB', (renderer.canvas_width, renderer.canvas_height))
|
||||
renderer.draw = ImageDraw.Draw(renderer.canvas)
|
||||
|
||||
|
||||
def set_screenshot_filename(self, filename:str):
|
||||
self.screenshot_filename = filename
|
||||
|
||||
|
||||
def set_screenshot_path(self, path):
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
self.screenshot_path = path
|
||||
|
||||
|
||||
def show_image(self, image=None, alpha_overlay=None, is_background_thread: bool = False):
|
||||
if is_background_thread:
|
||||
return
|
||||
|
||||
if alpha_overlay:
|
||||
if image == None:
|
||||
image = self.canvas
|
||||
image = Image.alpha_composite(image, alpha_overlay)
|
||||
|
||||
if image:
|
||||
# Always write to the current canvas, rather than trying to replace it
|
||||
self.canvas.paste(image)
|
||||
|
||||
self.canvas.save(os.path.join(self.screenshot_path, self.screenshot_filename))
|
||||
raise ScreenshotComplete()
|
||||
|
||||
Reference in New Issue
Block a user