mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 15:08:25 +00:00
Generalizing reusable components
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from .buttons import *
|
||||
from .camera_process import *
|
||||
from .keyboard import Keyboard
|
||||
from .keyboard import Keyboard, TextEntryDisplay
|
||||
from .path import *
|
||||
from .qr import *
|
||||
from .ST7789 import *
|
||||
@@ -341,3 +341,36 @@ class Keyboard:
|
||||
raise Exception(f"""`selected_letter` "{selected_letter}" not found in keyboard""")
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class TextEntryDisplay:
|
||||
draw: any
|
||||
rect: (int,int,int,int)
|
||||
font: any
|
||||
font_color: any
|
||||
is_centered: bool = True
|
||||
cur_text: str = " "
|
||||
|
||||
|
||||
def render(self, cur_text=None):
|
||||
""" Render the live text entry display """
|
||||
if cur_text:
|
||||
self.cur_text = cur_text
|
||||
self.draw.rectangle(self.rect, fill="black")
|
||||
|
||||
cursor_block_width = 18
|
||||
cursor_block_height = 33
|
||||
|
||||
# Draw n-1 of the selected letters
|
||||
tw, th = self.font.getsize(self.cur_text[:-1])
|
||||
if self.is_centered:
|
||||
word_offset = int(self.rect[2] - tw - cursor_block_width)/2
|
||||
else:
|
||||
word_offset = 0
|
||||
self.draw.text((word_offset, 2), self.cur_text[:-1], fill=self.font_color, font=self.font)
|
||||
|
||||
# Draw the highlighted cursor block
|
||||
cursor_block_offset = word_offset + tw - 1
|
||||
self.draw.rectangle((cursor_block_offset,2, cursor_block_offset + cursor_block_width, cursor_block_height), fill="#111")
|
||||
self.draw.text((cursor_block_offset + 1, 2), self.cur_text[-1], fill=self.font_color, font=self.font)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import time
|
||||
|
||||
# Internal file class dependencies
|
||||
from . import View
|
||||
from seedsigner.helpers import B, QR, CameraPoll, Keyboard
|
||||
from seedsigner.helpers import B, QR, CameraPoll, Keyboard, TextEntryDisplay
|
||||
|
||||
|
||||
class SeedToolsView(View):
|
||||
@@ -198,49 +198,10 @@ class SeedToolsView(View):
|
||||
)
|
||||
|
||||
|
||||
def render_previous_button(highlight=False):
|
||||
# Set up the "back" arrow in the upper left
|
||||
arrow = "<"
|
||||
word_font = View.ROBOTOCONDENSED_BOLD_26
|
||||
tw, th = word_font.getsize(arrow)
|
||||
if highlight:
|
||||
View.draw.rectangle((0,0, tw + 6, th + 6), fill=View.color)
|
||||
View.draw.text((3, 3), arrow, fill="black", font=word_font)
|
||||
else:
|
||||
View.draw.rectangle((0,0, tw + 6, th + 6), fill="black")
|
||||
View.draw.text((3, 3), arrow, fill=View.color, font=word_font)
|
||||
|
||||
return tw + 6
|
||||
|
||||
|
||||
def render_text_entry_display(draw=View.draw):
|
||||
""" Internal helper method to render the live text entry display at the top.
|
||||
(has access to all vars in the parent's context)
|
||||
"""
|
||||
draw.rectangle((previous_button_width,0, View.canvas_width,text_entry_display_height), fill="black")
|
||||
|
||||
# Render the live text entry display
|
||||
title = f"#{num_word}: {''.join(self.letters)}"
|
||||
|
||||
cursor_block_width = 18
|
||||
cursor_block_height = 33
|
||||
|
||||
# Draw n-1 of the selected letters
|
||||
word_font = View.ROBOTOCONDENSED_BOLD_26
|
||||
tw, th = word_font.getsize(title[:-1])
|
||||
word_offset = int(View.canvas_width - tw - cursor_block_width)/2
|
||||
draw.text((word_offset, 2), title[:-1], fill=View.color, font=word_font)
|
||||
|
||||
# Draw the highlighted cursor block
|
||||
cursor_block_offset = word_offset + tw - 1
|
||||
draw.rectangle((cursor_block_offset,2, cursor_block_offset + cursor_block_width, cursor_block_height), fill="#111")
|
||||
draw.text((cursor_block_offset + 1, 2), ''.join(self.letters[-1:]), fill=View.color, font=word_font)
|
||||
|
||||
|
||||
# Clear the screen
|
||||
View.draw.rectangle((0,0, View.canvas_width,View.canvas_height), fill="black")
|
||||
|
||||
previous_button_width = render_previous_button()
|
||||
self.render_previous_button()
|
||||
previous_button_is_active = False
|
||||
arrow_up_is_active = False
|
||||
arrow_down_is_active = False
|
||||
@@ -261,8 +222,18 @@ class SeedToolsView(View):
|
||||
rect=(0,text_entry_display_height + 1, keyboard_width,240),
|
||||
auto_wrap=[Keyboard.WRAP_LEFT, Keyboard.WRAP_RIGHT])
|
||||
|
||||
# Initialize the current letters/current matches
|
||||
# Render the top text entry display
|
||||
self.letters = initial_letters
|
||||
text_entry_display = TextEntryDisplay(
|
||||
View.draw,
|
||||
rect=(self.previous_button_width,0, View.canvas_width,text_entry_display_height),
|
||||
font=View.ROBOTOCONDENSED_BOLD_26,
|
||||
font_color=View.color,
|
||||
cur_text="".join(self.letters)
|
||||
)
|
||||
text_entry_display.render()
|
||||
|
||||
# Initialize the current matches
|
||||
self.possible_words = []
|
||||
if len(self.letters) > 1:
|
||||
self.letters.append(" ") # "Lock in" the last letter as if KEY_PRESS
|
||||
@@ -274,9 +245,6 @@ class SeedToolsView(View):
|
||||
keyboard.render_keys()
|
||||
render_possible_matches()
|
||||
|
||||
# Render the top text entry display
|
||||
render_text_entry_display()
|
||||
|
||||
View.DispShowImage()
|
||||
|
||||
# Start the interactive update loop
|
||||
@@ -295,13 +263,13 @@ class SeedToolsView(View):
|
||||
input = Keyboard.ENTER_BOTTOM
|
||||
# Re-render it without the highlight
|
||||
previous_button_is_active = False
|
||||
render_previous_button()
|
||||
self.render_previous_button()
|
||||
|
||||
elif input == B.KEY_DOWN:
|
||||
input = Keyboard.ENTER_TOP
|
||||
# Re-render it without the highlight
|
||||
previous_button_is_active = False
|
||||
render_previous_button()
|
||||
self.render_previous_button()
|
||||
|
||||
elif input in [B.KEY_RIGHT, B.KEY_LEFT]:
|
||||
# no action in this context
|
||||
@@ -310,7 +278,7 @@ class SeedToolsView(View):
|
||||
ret_val = keyboard.update_from_input(input)
|
||||
|
||||
if ret_val in Keyboard.EXIT_DIRECTIONS:
|
||||
render_previous_button(highlight=True)
|
||||
self.render_previous_button(highlight=True)
|
||||
previous_button_is_active = True
|
||||
|
||||
elif ret_val in Keyboard.ADDITIONAL_KEYS:
|
||||
@@ -378,7 +346,7 @@ class SeedToolsView(View):
|
||||
# Animate the selection storage, then return the word to the caller
|
||||
self.letters = list(final_selection + " ")
|
||||
render_possible_matches(highlight_word=final_selection)
|
||||
render_text_entry_display()
|
||||
text_entry_display.render("".join(self.letters))
|
||||
View.DispShowImage()
|
||||
|
||||
return final_selection
|
||||
@@ -433,11 +401,48 @@ class SeedToolsView(View):
|
||||
render_possible_matches()
|
||||
|
||||
# Render the text entry display and cursor block
|
||||
render_text_entry_display()
|
||||
text_entry_display.render("".join(self.letters))
|
||||
|
||||
View.DispShowImage()
|
||||
|
||||
|
||||
def draw_passphrase_keyboard_entry(self):
|
||||
|
||||
# Clear the screen
|
||||
View.draw.rectangle((0,0, View.canvas_width,View.canvas_height), fill="black")
|
||||
|
||||
self.render_previous_button()
|
||||
previous_button_is_active = False
|
||||
|
||||
# Have to ensure that we don't carry any effects from a previous run
|
||||
# TODO: This shouldn't be a member var
|
||||
self.passphrase = " "
|
||||
|
||||
# Set up the keyboard params
|
||||
right_key_nav_width = 50
|
||||
keyboard_width = View.canvas_width - right_key_nav_width
|
||||
text_entry_display_height = 39
|
||||
|
||||
keyboard = Keyboard(View.draw,
|
||||
charset=list("1234567890").append(SeedToolsView.ALPHABET),
|
||||
rows=4,
|
||||
cols=10,
|
||||
rect=(0,text_entry_display_height + 1, keyboard_width,240),
|
||||
auto_wrap=[Keyboard.WRAP_LEFT, Keyboard.WRAP_RIGHT, Keyboard.WRAP_TOP, Keyboard.WRAP_BOTTOM])
|
||||
|
||||
# Render the top text entry display
|
||||
text_entry_display = TextEntryDisplay(
|
||||
View.draw,
|
||||
rect=(self.previous_button_width,0, View.canvas_width,text_entry_display_height),
|
||||
font=View.ROBOTOCONDENSED_BOLD_26,
|
||||
font_color=View.color,
|
||||
is_centered=False,
|
||||
cur_text=''.join(self.passphrase)
|
||||
)
|
||||
text_entry_display.render()
|
||||
|
||||
View.DispShowImage()
|
||||
|
||||
def gather_words_up(self):
|
||||
View.draw.polygon([(8 + ((len(self.letters)-1)*30), 85) , (14 + ((len(self.letters)-1)*30), 69) , (20 + ((len(self.letters)-1)*30), 85 )], outline=View.color, fill=View.color)
|
||||
View.DispShowImage()
|
||||
@@ -551,10 +556,10 @@ class SeedToolsView(View):
|
||||
|
||||
return
|
||||
|
||||
|
||||
###
|
||||
### Display Gather PassPhrase Screen
|
||||
###
|
||||
|
||||
def display_gather_passphrase_screen(self, slot_num = 0) -> str:
|
||||
self.reset()
|
||||
self.pass_letter = "a"
|
||||
|
||||
@@ -64,6 +64,7 @@ class View:
|
||||
bus = 0
|
||||
device = 0
|
||||
disp = None
|
||||
previous_button_width = None
|
||||
|
||||
def __init__(self, controller) -> None:
|
||||
|
||||
@@ -259,3 +260,24 @@ class View:
|
||||
def display_blank_screen(self):
|
||||
View.draw.rectangle((0, 0, View.canvas_width, View.canvas_height), outline=0, fill=0)
|
||||
View.DispShowImage()
|
||||
|
||||
|
||||
###
|
||||
### Reusable components
|
||||
###
|
||||
def render_previous_button(self, highlight=False):
|
||||
# Set up the "back" arrow in the upper left
|
||||
arrow = "<"
|
||||
word_font = View.ROBOTOCONDENSED_BOLD_26
|
||||
padding = 3
|
||||
tw, th = word_font.getsize(arrow)
|
||||
self.previous_button_width = tw + 2 * padding
|
||||
if highlight:
|
||||
View.draw.rectangle((0,0, tw + 2 * padding, th + 2 * padding), fill=View.color)
|
||||
View.draw.text((padding, padding), arrow, fill="black", font=word_font)
|
||||
else:
|
||||
View.draw.rectangle((0,0, tw + 2 * padding, th + 2 * padding), fill="black")
|
||||
View.draw.text((padding, padding), arrow, fill=View.color, font=word_font)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
if __name__ == "__main__":
|
||||
import qrcode
|
||||
import sys
|
||||
from embit import bip39
|
||||
|
||||
print(sys.argv)
|
||||
seed_phrase = sys.argv[1:]
|
||||
print(seed_phrase)
|
||||
|
||||
data = ""
|
||||
for word in seed_phrase:
|
||||
index = bip39.WORDLIST.index(word)
|
||||
data += str("%04d" % index)
|
||||
|
||||
qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=5, border=3)
|
||||
qr.add_data(data)
|
||||
qr.make(fit=True)
|
||||
qr.make_image(fill_color="black", back_color="white").resize((240,240)).convert('RGB').show()
|
||||
Reference in New Issue
Block a user