You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.9 KiB
158 lines
4.9 KiB
![]()
8 years ago
|
from micropython import const
|
||
![]()
6 years ago
|
|
||
![]()
4 years ago
|
from trezor import config, res, ui
|
||
![]()
7 years ago
|
from trezor.crypto import random
|
||
|
from trezor.ui import display
|
||
![]()
4 years ago
|
|
||
|
from .button import Button, ButtonCancel, ButtonClear, ButtonConfirm, ButtonMono
|
||
![]()
8 years ago
|
|
||
![]()
5 years ago
|
if False:
|
||
![]()
4 years ago
|
from trezor import loop
|
||
|
from typing import Iterable, Optional, Tuple
|
||
![]()
8 years ago
|
|
||
![]()
5 years ago
|
|
||
|
def digit_area(i: int) -> ui.Area:
|
||
![]()
7 years ago
|
if i == 9: # 0-position
|
||
|
i = 10 # display it in the middle
|
||
![]()
7 years ago
|
return ui.grid(i + 3) # skip the first line
|
||
![]()
8 years ago
|
|
||
|
|
||
![]()
5 years ago
|
def generate_digits() -> Iterable[int]:
|
||
![]()
6 years ago
|
digits = list(range(0, 10)) # 0-9
|
||
![]()
8 years ago
|
random.shuffle(digits)
|
||
![]()
5 years ago
|
# We lay out the buttons top-left to bottom-right, but the order
|
||
|
# of the digits is defined as bottom-left to top-right (on numpad).
|
||
|
return digits[6:] + digits[3:6] + digits[:3]
|
||
![]()
8 years ago
|
|
||
|
|
||
![]()
5 years ago
|
class PinInput(ui.Component):
|
||
![]()
5 years ago
|
def __init__(self, prompt: str, subprompt: Optional[str], pin: str) -> None:
|
||
![]()
4 years ago
|
super().__init__()
|
||
![]()
5 years ago
|
self.prompt = prompt
|
||
|
self.subprompt = subprompt
|
||
![]()
8 years ago
|
self.pin = pin
|
||
![]()
8 years ago
|
|
||
![]()
5 years ago
|
def on_render(self) -> None:
|
||
![]()
5 years ago
|
if self.repaint:
|
||
|
if self.pin:
|
||
|
self.render_pin()
|
||
|
else:
|
||
|
self.render_prompt()
|
||
|
self.repaint = False
|
||
|
|
||
![]()
5 years ago
|
def render_pin(self) -> None:
|
||
![]()
5 years ago
|
display.bar(0, 0, ui.WIDTH, 50, ui.BG)
|
||
|
count = len(self.pin)
|
||
|
BOX_WIDTH = const(240)
|
||
|
DOT_SIZE = const(10)
|
||
|
PADDING = const(14)
|
||
|
RENDER_Y = const(20)
|
||
|
render_x = (BOX_WIDTH - count * PADDING) // 2
|
||
|
for i in range(0, count):
|
||
|
display.bar_radius(
|
||
|
render_x + i * PADDING, RENDER_Y, DOT_SIZE, DOT_SIZE, ui.GREY, ui.BG, 4
|
||
|
)
|
||
![]()
7 years ago
|
|
||
![]()
5 years ago
|
def render_prompt(self) -> None:
|
||
![]()
5 years ago
|
display.bar(0, 0, ui.WIDTH, 50, ui.BG)
|
||
|
if self.subprompt:
|
||
|
display.text_center(ui.WIDTH // 2, 20, self.prompt, ui.BOLD, ui.GREY, ui.BG)
|
||
|
display.text_center(
|
||
|
ui.WIDTH // 2, 46, self.subprompt, ui.NORMAL, ui.GREY, ui.BG
|
||
|
)
|
||
|
else:
|
||
|
display.text_center(ui.WIDTH // 2, 36, self.prompt, ui.BOLD, ui.GREY, ui.BG)
|
||
![]()
8 years ago
|
|
||
![]()
6 years ago
|
|
||
![]()
5 years ago
|
class PinButton(Button):
|
||
![]()
5 years ago
|
def __init__(self, index: int, digit: int, dialog: "PinDialog"):
|
||
|
self.dialog = dialog
|
||
![]()
5 years ago
|
super().__init__(digit_area(index), str(digit), ButtonMono)
|
||
![]()
6 years ago
|
|
||
![]()
5 years ago
|
def on_click(self) -> None:
|
||
|
self.dialog.assign(self.dialog.input.pin + self.text)
|
||
![]()
6 years ago
|
|
||
![]()
5 years ago
|
|
||
|
CANCELLED = object()
|
||
|
|
||
|
|
||
|
class PinDialog(ui.Layout):
|
||
![]()
5 years ago
|
def __init__(
|
||
![]()
5 years ago
|
self,
|
||
|
prompt: str,
|
||
|
subprompt: Optional[str],
|
||
|
allow_cancel: bool = True,
|
||
|
maxlength: int = 9,
|
||
![]()
5 years ago
|
) -> None:
|
||
![]()
5 years ago
|
self.maxlength = maxlength
|
||
|
self.input = PinInput(prompt, subprompt, "")
|
||
|
|
||
|
icon_confirm = res.load(ui.ICON_CONFIRM)
|
||
|
self.confirm_button = Button(ui.grid(14), icon_confirm, ButtonConfirm)
|
||
![]()
5 years ago
|
self.confirm_button.on_click = self.on_confirm # type: ignore
|
||
![]()
5 years ago
|
self.confirm_button.disable()
|
||
![]()
5 years ago
|
|
||
|
icon_back = res.load(ui.ICON_BACK)
|
||
|
self.reset_button = Button(ui.grid(12), icon_back, ButtonClear)
|
||
![]()
5 years ago
|
self.reset_button.on_click = self.on_reset # type: ignore
|
||
![]()
5 years ago
|
|
||
|
if allow_cancel:
|
||
![]()
4 years ago
|
icon_lock = res.load(
|
||
|
ui.ICON_CANCEL if config.is_unlocked() else ui.ICON_LOCK
|
||
|
)
|
||
![]()
5 years ago
|
self.cancel_button = Button(ui.grid(12), icon_lock, ButtonCancel)
|
||
![]()
5 years ago
|
self.cancel_button.on_click = self.on_cancel # type: ignore
|
||
![]()
6 years ago
|
else:
|
||
![]()
5 years ago
|
self.cancel_button = Button(ui.grid(12), "")
|
||
|
self.cancel_button.disable()
|
||
![]()
8 years ago
|
|
||
![]()
5 years ago
|
self.pin_buttons = [
|
||
|
PinButton(i, d, self) for i, d in enumerate(generate_digits())
|
||
|
]
|
||
![]()
8 years ago
|
|
||
![]()
5 years ago
|
def dispatch(self, event: int, x: int, y: int) -> None:
|
||
![]()
5 years ago
|
self.input.dispatch(event, x, y)
|
||
|
if self.input.pin:
|
||
|
self.reset_button.dispatch(event, x, y)
|
||
|
else:
|
||
|
self.cancel_button.dispatch(event, x, y)
|
||
![]()
5 years ago
|
self.confirm_button.dispatch(event, x, y)
|
||
|
for btn in self.pin_buttons:
|
||
|
btn.dispatch(event, x, y)
|
||
![]()
7 years ago
|
|
||
![]()
5 years ago
|
def assign(self, pin: str) -> None:
|
||
![]()
5 years ago
|
if len(pin) > self.maxlength:
|
||
|
return
|
||
![]()
6 years ago
|
for btn in self.pin_buttons:
|
||
![]()
5 years ago
|
if len(pin) < self.maxlength:
|
||
![]()
6 years ago
|
btn.enable()
|
||
![]()
5 years ago
|
else:
|
||
|
btn.disable()
|
||
|
if pin:
|
||
![]()
5 years ago
|
self.confirm_button.enable()
|
||
![]()
5 years ago
|
self.reset_button.enable()
|
||
|
self.cancel_button.disable()
|
||
|
else:
|
||
![]()
5 years ago
|
self.confirm_button.disable()
|
||
![]()
5 years ago
|
self.reset_button.disable()
|
||
|
self.cancel_button.enable()
|
||
|
self.input.pin = pin
|
||
|
self.input.repaint = True
|
||
|
|
||
![]()
5 years ago
|
def on_reset(self) -> None:
|
||
![]()
5 years ago
|
self.assign("")
|
||
|
|
||
![]()
5 years ago
|
def on_cancel(self) -> None:
|
||
![]()
5 years ago
|
raise ui.Result(CANCELLED)
|
||
|
|
||
![]()
5 years ago
|
def on_confirm(self) -> None:
|
||
![]()
5 years ago
|
if self.input.pin:
|
||
|
raise ui.Result(self.input.pin)
|
||
![]()
4 years ago
|
|
||
|
if __debug__:
|
||
|
|
||
|
def create_tasks(self) -> Tuple[loop.Task, ...]:
|
||
|
from apps.debug import input_signal
|
||
|
|
||
|
return super().create_tasks() + (input_signal(),)
|