mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 15:08:25 +00:00
Tweaks to passphrase flow, settings; SeedWordsView now highlighting four words at a time
This commit is contained in:
@@ -53,6 +53,7 @@ All of the above!
|
||||
These features will not be included in the initial v0.5.0 release and will have varying degrees of priority for subsequent releases (or possibly not at all).
|
||||
|
||||
* Multisig wallet descriptor QR scan(?) and addr verification(?)
|
||||
* Sign taproot txs
|
||||
* Multi-language support (Transifex free for open source projects)
|
||||
* Multisig: sign PSBT with multiple keys at once.
|
||||
* Custom OS, possibly with swappable SD card PSBT and multisig wallet descriptor storage
|
||||
|
||||
@@ -517,6 +517,7 @@ class LargeButtonScreen(BaseTopNavScreen):
|
||||
button_font_name: str = GUIConstants.BUTTON_FONT_NAME
|
||||
button_font_size: int = 20
|
||||
button_selected_color: str = GUIConstants.ACCENT_COLOR
|
||||
selected_button: int = 0
|
||||
|
||||
def __post_init__(self):
|
||||
super().__post_init__()
|
||||
@@ -570,8 +571,7 @@ class LargeButtonScreen(BaseTopNavScreen):
|
||||
if i == 1:
|
||||
button_start_y += button_height + GUIConstants.COMPONENT_PADDING
|
||||
|
||||
self.buttons[0].is_selected = True
|
||||
self.selected_button = 0
|
||||
self.buttons[self.selected_button].is_selected = True
|
||||
|
||||
|
||||
def _run(self):
|
||||
|
||||
@@ -443,43 +443,49 @@ class SeedOptionsScreen(ButtonListScreen):
|
||||
|
||||
@dataclass
|
||||
class SeedWordsScreen(WarningEdgesMixin, ButtonListScreen):
|
||||
title: str = "Seed Words"
|
||||
seed: Seed = None
|
||||
is_first_page: bool = True
|
||||
page_index: int = 0
|
||||
num_pages: int = 3
|
||||
is_bottom_list: bool = True
|
||||
warning_color: str = GUIConstants.DIRE_WARNING_COLOR
|
||||
|
||||
|
||||
def __post_init__(self):
|
||||
self.title = f"Seed Words: {self.page_index+1}/{self.num_pages}"
|
||||
super().__post_init__()
|
||||
|
||||
# Can only render 12 words per screen
|
||||
# Can only render 4 words per screen
|
||||
words_per_page = 4
|
||||
mnemonic = self.seed.mnemonic_display_list
|
||||
if len(mnemonic) == 12 or self.is_first_page:
|
||||
self.mnemonic = mnemonic[:12]
|
||||
else:
|
||||
self.mnemonic = mnemonic[12:]
|
||||
|
||||
# Slice the mnemonic to our current 4-word section
|
||||
self.mnemonic = mnemonic[self.page_index*words_per_page:(self.page_index + 1)*words_per_page]
|
||||
|
||||
self.body_x = 0
|
||||
self.body_y = self.top_nav.height - int(GUIConstants.COMPONENT_PADDING / 2)
|
||||
self.body_height = self.buttons[0].screen_y - self.body_y
|
||||
|
||||
# Have to supersample the whole body since it's all at the small font size
|
||||
supersampling_factor = 2
|
||||
font = Fonts.get_font(GUIConstants.BODY_FONT_NAME, 16 * supersampling_factor)
|
||||
supersampling_factor = 1
|
||||
font = Fonts.get_font(GUIConstants.BODY_FONT_NAME, (GUIConstants.TOP_NAV_TITLE_FONT_SIZE + 2) * supersampling_factor)
|
||||
|
||||
# Calc vertical placement for the numbers
|
||||
(number_x, number_y) = calc_text_centering(
|
||||
font=font,
|
||||
text="1234567890",
|
||||
is_text_centered=True,
|
||||
total_width=20 * supersampling_factor,
|
||||
total_height=20 * supersampling_factor
|
||||
)
|
||||
number_box_x = GUIConstants.EDGE_PADDING * supersampling_factor
|
||||
number_box_y = GUIConstants.COMPONENT_PADDING * supersampling_factor
|
||||
number_box_width = 20 * supersampling_factor
|
||||
number_box_height = 20 * supersampling_factor
|
||||
# Calc horizontal center based on longest word
|
||||
max_word_width = 0
|
||||
for word in self.mnemonic:
|
||||
(left, top, right, bottom) = font.getbbox(word, anchor="ls")
|
||||
if right > max_word_width:
|
||||
max_word_width = right
|
||||
|
||||
# Measure the max digit height for the numbering boxes, from baseline
|
||||
number_font = Fonts.get_font(GUIConstants.BODY_FONT_NAME, GUIConstants.BUTTON_FONT_SIZE * supersampling_factor)
|
||||
(left, top, right, bottom) = number_font.getbbox("24", anchor="ls")
|
||||
number_height = -1 * top
|
||||
number_width = right
|
||||
number_box_width = number_width + int(GUIConstants.COMPONENT_PADDING/2 * supersampling_factor)
|
||||
number_box_height = number_box_width
|
||||
|
||||
number_box_x = int((self.canvas_width * supersampling_factor - number_box_width - GUIConstants.COMPONENT_PADDING*supersampling_factor - max_word_width))/2
|
||||
number_box_y = GUIConstants.COMPONENT_PADDING * supersampling_factor
|
||||
|
||||
# Set up our temp supersampled rendering surface
|
||||
self.body_img = Image.new(
|
||||
@@ -490,37 +496,30 @@ class SeedWordsScreen(WarningEdgesMixin, ButtonListScreen):
|
||||
draw = ImageDraw.Draw(self.body_img)
|
||||
|
||||
for index, word in enumerate(self.mnemonic):
|
||||
if index == 6:
|
||||
# Start of the second column of words
|
||||
number_box_x = (int(self.canvas_width / 2) + 4) * supersampling_factor
|
||||
number_box_y = GUIConstants.COMPONENT_PADDING * supersampling_factor
|
||||
|
||||
draw.rounded_rectangle(
|
||||
(number_box_x, number_box_y, number_box_x + number_box_width, number_box_y + number_box_height),
|
||||
fill="#202020",
|
||||
radius=5 * supersampling_factor
|
||||
)
|
||||
if self.is_first_page:
|
||||
number_str = str(index + 1)
|
||||
else:
|
||||
number_str = str(index + 1 + 12)
|
||||
tw, th = font.getsize(number_str)
|
||||
baseline_y = number_box_y + number_box_height - int((number_box_height - number_height)/2)
|
||||
draw.text(
|
||||
(number_box_x + int((number_box_width - tw) / 2), number_box_y + number_y),
|
||||
font=font,
|
||||
text=number_str,
|
||||
fill="#0084ff"
|
||||
(number_box_x + int(number_box_width/2), baseline_y),
|
||||
font=number_font,
|
||||
text=str(self.page_index * words_per_page + index + 1),
|
||||
fill="#0084ff",
|
||||
anchor="ms" # Middle (centered), baSeline
|
||||
)
|
||||
|
||||
# Now draw the word
|
||||
draw.text(
|
||||
(number_box_x + number_box_width + (4 * supersampling_factor), number_box_y + number_y),
|
||||
(number_box_x + number_box_width + (GUIConstants.COMPONENT_PADDING * supersampling_factor), baseline_y),
|
||||
font=font,
|
||||
text=word,
|
||||
fill=GUIConstants.BODY_FONT_COLOR
|
||||
fill=GUIConstants.BODY_FONT_COLOR,
|
||||
anchor="ls", # Left, baSeline
|
||||
)
|
||||
|
||||
number_box_y += number_box_height + (4 * supersampling_factor)
|
||||
number_box_y += number_box_height + (int(1.5*GUIConstants.COMPONENT_PADDING) * supersampling_factor)
|
||||
|
||||
# Resize to target and sharpen final image
|
||||
self.body_img = self.body_img.resize((self.canvas_width, self.body_height), Image.LANCZOS)
|
||||
|
||||
@@ -42,7 +42,7 @@ class HardwareButtons(Singleton):
|
||||
cls._instance.cur_input = None # Track which direction or button was last pressed
|
||||
cls._instance.cur_input_started = None # Track when that input began
|
||||
cls._instance.last_input_time = int(time.time() * 1000) # How long has it been since the last input?
|
||||
cls._instance.first_repeat_threshold = 175 # Long-press time required before returning continuous input
|
||||
cls._instance.first_repeat_threshold = 225 # Long-press time required before returning continuous input
|
||||
cls._instance.next_repeat_threshold = 250 # Amount of time where we no longer consider input a continuous hold
|
||||
|
||||
return cls._instance
|
||||
|
||||
@@ -74,6 +74,8 @@ class Settings(Singleton):
|
||||
if type(new_settings[entry.attr_name]) == str:
|
||||
# Break comma-separated SettingsQR input into List
|
||||
new_settings[entry.attr_name] = new_settings[entry.attr_name].split(",")
|
||||
|
||||
# TODO: If value is not in entry.selection_options...
|
||||
|
||||
|
||||
# Can't just merge the _data dict; have to replace keys they have in common
|
||||
|
||||
@@ -13,6 +13,14 @@ class SettingsConstants:
|
||||
(OPTION__ENABLED, "Enabled"),
|
||||
(OPTION__DISABLED, "Disabled"),
|
||||
]
|
||||
OPTIONS__PROMPT_REQUIRED_DISABLED = [
|
||||
(OPTION__PROMPT, "Prompt"),
|
||||
(OPTION__REQUIRED, "Required"),
|
||||
(OPTION__DISABLED, "Disabled"),
|
||||
]
|
||||
OPTIONS__ENABLED_DISABLED_REQUIRED = OPTIONS__ENABLED_DISABLED +[
|
||||
(OPTION__REQUIRED, "Required"),
|
||||
]
|
||||
OPTIONS__ENABLED_DISABLED_PROMPT = OPTIONS__ENABLED_DISABLED + [
|
||||
(OPTION__PROMPT, "Prompt"),
|
||||
]
|
||||
@@ -244,6 +252,18 @@ class SettingsEntry:
|
||||
return display_name
|
||||
|
||||
|
||||
def get_selection_option_value_by_display_name(self, display_name: str):
|
||||
for option in self.selection_options:
|
||||
if type(option) == tuple:
|
||||
option_value = option[0]
|
||||
option_display_name = option[1]
|
||||
else:
|
||||
option_value = option
|
||||
option_display_name = option
|
||||
if option_display_name == display_name:
|
||||
return option_value
|
||||
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
if self.selection_options:
|
||||
selection_options = []
|
||||
@@ -377,7 +397,7 @@ class SettingsDefinition:
|
||||
display_name="BIP-39 passphrase",
|
||||
type=SettingsConstants.TYPE__SELECT_1,
|
||||
visibility=SettingsConstants.VISIBILITY__ADVANCED,
|
||||
selection_options=SettingsConstants.ALL_OPTIONS,
|
||||
selection_options=SettingsConstants.OPTIONS__ENABLED_DISABLED_REQUIRED,
|
||||
default_value=SettingsConstants.OPTION__ENABLED),
|
||||
|
||||
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
|
||||
|
||||
@@ -3,7 +3,7 @@ from seedsigner.models.psbt_parser import PSBTParser
|
||||
|
||||
from seedsigner.models.settings import SettingsConstants
|
||||
from seedsigner.views.psbt_views import PSBTSelectSeedView
|
||||
from seedsigner.views.seed_views import SeedAddPassphrasePromptView, SeedAddPassphraseView
|
||||
from seedsigner.views.seed_views import SeedAddPassphraseView
|
||||
|
||||
from .view import BackStackView, MainMenuView, NotYetImplementedView, View, Destination
|
||||
|
||||
@@ -37,9 +37,7 @@ class ScanView(View):
|
||||
self.controller.storage.set_pending_seed(
|
||||
Seed(mnemonic=seed_mnemonic, wordlist_language_code=wordlist_language_code)
|
||||
)
|
||||
if self.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) == SettingsConstants.OPTION__PROMPT:
|
||||
return Destination(SeedAddPassphrasePromptView)
|
||||
elif self.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) == SettingsConstants.OPTION__REQUIRED:
|
||||
if self.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) == SettingsConstants.OPTION__REQUIRED:
|
||||
return Destination(SeedAddPassphraseView)
|
||||
else:
|
||||
return Destination(SeedFinalizeView)
|
||||
|
||||
@@ -4,6 +4,8 @@ import time
|
||||
from binascii import hexlify
|
||||
from embit.networks import NETWORKS
|
||||
|
||||
from seedsigner.models.settings_definition import SettingsDefinition
|
||||
|
||||
from .view import NotYetImplementedView, View, Destination, BackStackView, MainMenuView
|
||||
|
||||
from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerCustomIconConstants
|
||||
@@ -57,6 +59,9 @@ class SeedsMenuView(View):
|
||||
|
||||
|
||||
|
||||
"""****************************************************************************
|
||||
Loading seeds, passphrases, etc
|
||||
****************************************************************************"""
|
||||
class LoadSeedView(View):
|
||||
def run(self):
|
||||
SEED_QR = (" Scan a SeedQR", FontAwesomeIconConstants.QRCODE)
|
||||
@@ -189,9 +194,6 @@ class SeedMnemonicInvalidView(View):
|
||||
|
||||
|
||||
|
||||
"""****************************************************************************
|
||||
Loading seeds, passphrases, etc
|
||||
****************************************************************************"""
|
||||
class SeedFinalizeView(View):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -200,101 +202,27 @@ class SeedFinalizeView(View):
|
||||
|
||||
|
||||
def run(self):
|
||||
PASSPHRASE = ("Add Passphrase", FontAwesomeIconConstants.UNLOCK)
|
||||
FINALIZE = "Done"
|
||||
CANCEL = ("Cancel", None, None, "red")
|
||||
PASSPHRASE = ("Add Passphrase", FontAwesomeIconConstants.LOCK)
|
||||
button_data = []
|
||||
|
||||
if self.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) in [
|
||||
SettingsConstants.OPTION__ENABLED,
|
||||
SettingsConstants.OPTION__PROMPT,
|
||||
SettingsConstants.OPTION__REQUIRED]:
|
||||
if self.seed.passphrase:
|
||||
PASSPHRASE = "Edit Passphrase"
|
||||
button_data.append(PASSPHRASE)
|
||||
|
||||
button_data.append(FINALIZE)
|
||||
button_data.append(CANCEL)
|
||||
|
||||
if self.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) != SettingsConstants.OPTION__DISABLED:
|
||||
button_data.append(PASSPHRASE)
|
||||
|
||||
selected_menu_num = seed_screens.SeedFinalizeScreen(
|
||||
fingerprint=self.fingerprint,
|
||||
button_data=button_data,
|
||||
).display()
|
||||
|
||||
if button_data[selected_menu_num] == PASSPHRASE:
|
||||
return Destination(SeedAddPassphraseView)
|
||||
|
||||
elif button_data[selected_menu_num] == FINALIZE:
|
||||
if button_data[selected_menu_num] == FINALIZE:
|
||||
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] == CANCEL:
|
||||
return Destination(SeedDiscardView)
|
||||
|
||||
|
||||
|
||||
class SeedDiscardView(View):
|
||||
def __init__(self, seed_num: int = None):
|
||||
super().__init__()
|
||||
self.seed_num = seed_num
|
||||
print(f"self.seed_num: {self.seed_num}")
|
||||
if self.seed_num is not None:
|
||||
self.seed = self.controller.get_seed(self.seed_num)
|
||||
else:
|
||||
self.seed = self.controller.storage.pending_seed
|
||||
|
||||
|
||||
def run(self):
|
||||
KEEP = "Keep Seed"
|
||||
DISCARD = ("Discard", None, None, "red")
|
||||
button_data = [KEEP, DISCARD]
|
||||
|
||||
fingerprint = self.seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK))
|
||||
selected_menu_num = WarningScreen(
|
||||
title="Discard Seed?",
|
||||
warning_headline=None,
|
||||
warning_text=f"Remove seed {fingerprint} from memory?",
|
||||
show_back_button=False,
|
||||
button_data=button_data,
|
||||
).display()
|
||||
|
||||
print(f"selected_menu_num: {selected_menu_num}")
|
||||
|
||||
if button_data[selected_menu_num] == KEEP:
|
||||
if self.seed_num is not None:
|
||||
return Destination(SeedOptionsView, view_args={"seed_num": self.seed_num})
|
||||
else:
|
||||
return Destination(SeedFinalizeView)
|
||||
|
||||
elif button_data[selected_menu_num] == DISCARD:
|
||||
if self.seed_num is not None:
|
||||
self.controller.discard_seed(self.seed_num)
|
||||
else:
|
||||
self.controller.storage.clear_pending_seed()
|
||||
return Destination(MainMenuView)
|
||||
|
||||
|
||||
|
||||
class SeedAddPassphrasePromptView(View):
|
||||
def run(self):
|
||||
YES = "Yes"
|
||||
NO = "No"
|
||||
button_data = [YES, NO]
|
||||
|
||||
selected_menu_num = LargeButtonScreen(
|
||||
title="Add Passphrase?",
|
||||
button_data=button_data
|
||||
).display()
|
||||
|
||||
if selected_menu_num == RET_CODE__BACK_BUTTON:
|
||||
return Destination(BackStackView)
|
||||
|
||||
if button_data[selected_menu_num] == YES:
|
||||
elif button_data[selected_menu_num] == PASSPHRASE:
|
||||
return Destination(SeedAddPassphraseView)
|
||||
|
||||
elif button_data[selected_menu_num] == NO:
|
||||
return Destination(SeedFinalizeView)
|
||||
|
||||
|
||||
|
||||
class SeedAddPassphraseView(View):
|
||||
@@ -327,8 +255,8 @@ class SeedReviewPassphraseView(View):
|
||||
|
||||
def run(self):
|
||||
EDIT = "Edit passphrase"
|
||||
CONTINUE = "Continue"
|
||||
button_data = [EDIT, CONTINUE]
|
||||
DONE = "Done"
|
||||
button_data = [EDIT, DONE]
|
||||
|
||||
# Get the before/after fingerprints
|
||||
network = self.settings.get_value(SettingsConstants.SETTING__NETWORK)
|
||||
@@ -348,21 +276,60 @@ class SeedReviewPassphraseView(View):
|
||||
show_back_button=False,
|
||||
).display()
|
||||
|
||||
if selected_menu_num == RET_CODE__BACK_BUTTON:
|
||||
return Destination(BackStackView)
|
||||
|
||||
elif button_data[selected_menu_num] == EDIT:
|
||||
if button_data[selected_menu_num] == EDIT:
|
||||
return Destination(SeedAddPassphraseView)
|
||||
|
||||
elif button_data[selected_menu_num] == CONTINUE:
|
||||
return Destination(SeedFinalizeView)
|
||||
elif button_data[selected_menu_num] == DONE:
|
||||
seed_num = self.controller.storage.finalize_pending_seed()
|
||||
return Destination(SeedOptionsView, view_args={"seed_num": seed_num})
|
||||
|
||||
|
||||
|
||||
class SeedDiscardView(View):
|
||||
def __init__(self, seed_num: int = None):
|
||||
super().__init__()
|
||||
self.seed_num = seed_num
|
||||
print(f"self.seed_num: {self.seed_num}")
|
||||
if self.seed_num is not None:
|
||||
self.seed = self.controller.get_seed(self.seed_num)
|
||||
else:
|
||||
self.seed = self.controller.storage.pending_seed
|
||||
|
||||
|
||||
def run(self):
|
||||
KEEP = "Keep Seed"
|
||||
DISCARD = ("Discard", None, None, "red")
|
||||
button_data = [KEEP, DISCARD]
|
||||
|
||||
fingerprint = self.seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK))
|
||||
selected_menu_num = WarningScreen(
|
||||
title="Discard Seed?",
|
||||
warning_headline=None,
|
||||
warning_text=f"Wipe seed {fingerprint} from the device?",
|
||||
show_back_button=False,
|
||||
button_data=button_data,
|
||||
).display()
|
||||
|
||||
print(f"selected_menu_num: {selected_menu_num}")
|
||||
|
||||
if button_data[selected_menu_num] == KEEP:
|
||||
if self.seed_num is not None:
|
||||
return Destination(SeedOptionsView, view_args={"seed_num": self.seed_num})
|
||||
else:
|
||||
return Destination(SeedFinalizeView)
|
||||
|
||||
elif button_data[selected_menu_num] == DISCARD:
|
||||
if self.seed_num is not None:
|
||||
self.controller.discard_seed(self.seed_num)
|
||||
else:
|
||||
self.controller.storage.clear_pending_seed()
|
||||
return Destination(MainMenuView)
|
||||
|
||||
|
||||
|
||||
"""****************************************************************************
|
||||
Views for actions on individual seeds:
|
||||
****************************************************************************"""
|
||||
|
||||
class SeedOptionsView(View):
|
||||
def __init__(self, seed_num: int):
|
||||
super().__init__()
|
||||
@@ -439,7 +406,7 @@ class SeedWordsWarningView(View):
|
||||
|
||||
|
||||
def run(self):
|
||||
destination = Destination(SeedWordsView, view_args={"seed_num": self.seed_num})
|
||||
destination = Destination(SeedWordsView, view_args={"seed_num": self.seed_num, "page_index": 0})
|
||||
if self.settings.get_value(SettingsConstants.SETTING__DIRE_WARNINGS) == SettingsConstants.OPTION__DISABLED:
|
||||
# Forward straight to showing the words
|
||||
destination.skip_current_view = True
|
||||
@@ -459,38 +426,39 @@ class SeedWordsWarningView(View):
|
||||
|
||||
|
||||
class SeedWordsView(View):
|
||||
def __init__(self, seed_num: int, is_first_page: bool = True):
|
||||
def __init__(self, seed_num: int, page_index: int = 0):
|
||||
super().__init__()
|
||||
self.seed_num = seed_num
|
||||
self.seed = self.controller.get_seed(self.seed_num)
|
||||
self.is_first_page = is_first_page
|
||||
self.page_index = page_index
|
||||
self.num_pages=int(len(self.seed.mnemonic_list)/4)
|
||||
|
||||
|
||||
def run(self):
|
||||
NEXT_12 = "Next"
|
||||
SEED_OPTIONS = "Seed Options"
|
||||
NEXT = "Next"
|
||||
DONE = "Done"
|
||||
|
||||
button_data = []
|
||||
if self.is_first_page and len(self.seed.mnemonic_list) == 24:
|
||||
button_data.append(NEXT_12)
|
||||
if self.page_index < self.num_pages - 1:
|
||||
button_data.append(NEXT)
|
||||
else:
|
||||
button_data.append(SEED_OPTIONS)
|
||||
button_data.append(DONE)
|
||||
|
||||
selected_menu_num = seed_screens.SeedWordsScreen(
|
||||
seed=self.seed,
|
||||
is_first_page=self.is_first_page,
|
||||
page_index=self.page_index,
|
||||
num_pages=self.num_pages,
|
||||
button_data=button_data,
|
||||
).display()
|
||||
|
||||
if selected_menu_num == RET_CODE__BACK_BUTTON:
|
||||
return Destination(BackStackView)
|
||||
|
||||
if button_data[selected_menu_num] == NEXT_12:
|
||||
# Go on to page 2
|
||||
return Destination(SeedWordsView, view_args={"seed_num": self.seed_num, "is_first_page": False})
|
||||
if button_data[selected_menu_num] == NEXT:
|
||||
return Destination(SeedWordsView, view_args={"seed_num": self.seed_num, "page_index": self.page_index + 1})
|
||||
|
||||
elif button_data[selected_menu_num] == SEED_OPTIONS:
|
||||
# Back to SeedOptions for this seed; cannot back ("<") to this View.
|
||||
elif button_data[selected_menu_num] == DONE:
|
||||
# Must clear history to avoid BACK button returning to private info
|
||||
return Destination(SeedOptionsView, view_args={"seed_num": self.seed_num}, clear_history=True)
|
||||
|
||||
|
||||
@@ -513,7 +481,7 @@ class SeedExportXpubSigTypeView(View):
|
||||
MULTISIG = "Multisig"
|
||||
button_data=[SINGLE_SIG, MULTISIG]
|
||||
|
||||
selected_menu_num = LargeButtonScreen(
|
||||
selected_menu_num = ButtonListScreen(
|
||||
title="Export Xpub",
|
||||
button_data=button_data
|
||||
).display()
|
||||
@@ -543,17 +511,21 @@ class SeedExportXpubScriptTypeView(View):
|
||||
args["script_type"] = self.settings.get_value(SettingsConstants.SETTING__SCRIPT_TYPES)[0]
|
||||
return Destination(SeedExportXpubCoordinatorView, view_args=args, skip_current_view=True)
|
||||
|
||||
button_data = []
|
||||
for script_type in self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__SCRIPT_TYPES):
|
||||
button_data.append(script_type)
|
||||
selected_menu_num = ButtonListScreen(
|
||||
title="Export Xpub",
|
||||
is_button_text_centered=False,
|
||||
is_bottom_list=True,
|
||||
button_data=self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__SCRIPT_TYPES),
|
||||
button_data=button_data,
|
||||
).display()
|
||||
|
||||
if selected_menu_num < len(SettingsConstants.ALL_SCRIPT_TYPES):
|
||||
args["script_type"] = SettingsConstants.ALL_SCRIPT_TYPES[selected_menu_num][0]
|
||||
script_types_settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__SCRIPT_TYPES)
|
||||
selected_display_name = button_data[selected_menu_num]
|
||||
args["script_type"] = script_types_settings_entry.get_selection_option_value_by_display_name(selected_display_name)
|
||||
|
||||
if SettingsConstants.ALL_SCRIPT_TYPES[selected_menu_num][0] == SettingsConstants.CUSTOM_DERIVATION:
|
||||
if button_data[selected_menu_num] == SettingsConstants.CUSTOM_DERIVATION:
|
||||
return Destination(SeedExportXpubCustomDerivationView, view_args=args)
|
||||
|
||||
return Destination(SeedExportXpubCoordinatorView, view_args=args)
|
||||
@@ -615,7 +587,6 @@ class SeedExportXpubCoordinatorView(View):
|
||||
selected_menu_num = ButtonListScreen(
|
||||
title="Export Xpub",
|
||||
is_button_text_centered=False,
|
||||
is_bottom_list=True,
|
||||
button_data=self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS),
|
||||
).display()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import time
|
||||
|
||||
from PIL import Image
|
||||
from PIL.ImageOps import autocontrast
|
||||
from seedsigner.gui.screens.screen import LargeButtonScreen
|
||||
|
||||
from seedsigner.hardware.camera import Camera
|
||||
from seedsigner.gui.components import FontAwesomeIconConstants
|
||||
@@ -45,6 +46,9 @@ class ToolsMenuView(View):
|
||||
|
||||
|
||||
|
||||
"""****************************************************************************
|
||||
Image entropy Views
|
||||
****************************************************************************"""
|
||||
class ToolsImageEntropyLivePreviewView(View):
|
||||
def run(self):
|
||||
self.controller.image_entropy_preview_frames = None
|
||||
@@ -99,10 +103,14 @@ class ToolsImageEntropyMnemonicLengthView(View):
|
||||
TWENTYFOUR_WORDS = "24 words"
|
||||
button_data = [TWELVE_WORDS, TWENTYFOUR_WORDS]
|
||||
|
||||
selected_menu_num = ButtonListScreen(
|
||||
# selected_menu_num = ButtonListScreen(
|
||||
# title="Mnemonic Length?",
|
||||
# button_data=button_data,
|
||||
# ).display()
|
||||
|
||||
selected_menu_num = LargeButtonScreen(
|
||||
title="Mnemonic Length?",
|
||||
button_data=button_data,
|
||||
is_bottom_list=True,
|
||||
).display()
|
||||
|
||||
if selected_menu_num == RET_CODE__BACK_BUTTON:
|
||||
@@ -164,6 +172,9 @@ class ToolsImageEntropyMnemonicLengthView(View):
|
||||
|
||||
|
||||
|
||||
"""****************************************************************************
|
||||
Calc final word Views
|
||||
****************************************************************************"""
|
||||
class ToolsCalcFinalWordNumWordsView(View):
|
||||
def run(self):
|
||||
TWELVE = "12 words"
|
||||
|
||||
@@ -33,6 +33,12 @@ class BackStackView:
|
||||
As with http requests, Views can receive input vars to inform their behavior. Views
|
||||
can also prepare the next set of vars to set up the next View that should be
|
||||
displayed (akin to Flask's `return redirect(url, param1=x, param2=y))`).
|
||||
|
||||
Navigation guidance:
|
||||
"Next" - Continue to next step
|
||||
"Done" - End of flow, return to entry point (non-destructive)
|
||||
"OK/Close" - Exit current screen (non-destructive)
|
||||
"Cancel" - End task and return to entry point (destructive)
|
||||
"""
|
||||
class View:
|
||||
def __init__(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user