Exemple #1
0
class HoldToConfirmDialog(Widget):
    def __init__(
        self,
        content,
        hold="Hold to confirm",
        button_style=ui.BTN_CONFIRM,
        loader_style=ui.LDR_DEFAULT,
    ):
        self.content = content
        self.button = Button(ui.grid(4, n_x=1), hold, style=button_style)
        self.loader = Loader(style=loader_style)

        if content.__class__.__iter__ is not Widget.__iter__:
            raise TypeError(
                "HoldToConfirmDialog does not support widgets with custom event loop"
            )

    def taint(self):
        super().taint()
        self.button.taint()
        self.content.taint()

    def render(self):
        self.button.render()
        if not self.loader.is_active():
            self.content.render()

    def touch(self, event, pos):
        button = self.button
        was_active = button.state == BTN_ACTIVE
        button.touch(event, pos)
        is_active = button.state == BTN_ACTIVE
        if is_active and not was_active:
            ui.display.clear()
            self.loader.start()
            return _STARTED
        if was_active and not is_active:
            self.content.taint()
            if self.loader.stop():
                return CONFIRMED
            else:
                return _STOPPED

    async def __iter__(self):
        result = None
        while result is None or result < 0:  # _STARTED or _STOPPED
            if self.loader.is_active():
                if __debug__:
                    result = await loop.spawn(self.loader,
                                              super().__iter__(),
                                              confirm_signal)
                else:
                    result = await loop.spawn(self.loader, super().__iter__())
            else:
                if __debug__:
                    result = await loop.spawn(super().__iter__(),
                                              confirm_signal)
                else:
                    result = await super().__iter__()
        return result
Exemple #2
0
class HoldToConfirmDialog(Widget):
    def __init__(
        self,
        content,
        hold="Hold to confirm",
        button_style=ui.BTN_CONFIRM,
        loader_style=ui.LDR_DEFAULT,
    ):
        self.content = content
        self.button = Button(ui.grid(4, n_x=1), hold, style=button_style)
        self.loader = Loader(style=loader_style)

    def taint(self):
        super().taint()
        self.button.taint()
        self.content.taint()

    def render(self):
        self.button.render()

    def touch(self, event, pos):
        button = self.button
        was_active = button.state == BTN_ACTIVE
        button.touch(event, pos)
        is_active = button.state == BTN_ACTIVE
        if is_active and not was_active:
            ui.display.clear()
            self.loader.start()
            return _STARTED
        if was_active and not is_active:
            self.content.taint()
            if self.loader.stop():
                return CONFIRMED
            else:
                return _STOPPED

    async def __iter__(self):
        result = None
        while result is None or result < 0:  # _STARTED or _STOPPED
            if self.loader.is_active():
                content_loop = self.loader
            else:
                content_loop = self.content
            confirm_loop = super().__iter__()  # default loop (render on touch)
            if __debug__:
                result = await loop.spawn(content_loop, confirm_loop,
                                          confirm_signal)
            else:
                result = await loop.spawn(content_loop, confirm_loop)
        return result
Exemple #3
0
class EntrySelector(Widget):
    def __init__(self, content):
        self.content = content
        self.device = Button(ui.grid(8, n_y=4, n_x=4, cells_x=4), "Device")
        self.host = Button(ui.grid(12, n_y=4, n_x=4, cells_x=4), "Host")

    def taint(self):
        super().taint()
        self.device.taint()
        self.host.taint()

    def render(self):
        self.device.render()
        self.host.render()

    def touch(self, event, pos):
        if self.device.touch(event, pos) == BTN_CLICKED:
            return DEVICE
        if self.host.touch(event, pos) == BTN_CLICKED:
            return HOST

    async def __iter__(self):
        return await loop.spawn(super().__iter__(), self.content)
Exemple #4
0
class WordSelector(Widget):
    def __init__(self, content):
        self.content = content
        self.w12 = Button(ui.grid(6, n_y=4, n_x=3, cells_y=2),
                          str(_W12),
                          style=ui.BTN_KEY)
        self.w18 = Button(ui.grid(7, n_y=4, n_x=3, cells_y=2),
                          str(_W18),
                          style=ui.BTN_KEY)
        self.w24 = Button(ui.grid(8, n_y=4, n_x=3, cells_y=2),
                          str(_W24),
                          style=ui.BTN_KEY)

    def taint(self):
        super().taint()
        self.w12.taint()
        self.w18.taint()
        self.w24.taint()

    def render(self):
        self.w12.render()
        self.w18.render()
        self.w24.render()

    def touch(self, event, pos):
        if self.w12.touch(event, pos) == BTN_CLICKED:
            return _W12
        if self.w18.touch(event, pos) == BTN_CLICKED:
            return _W18
        if self.w24.touch(event, pos) == BTN_CLICKED:
            return _W24

    async def __iter__(self):
        if __debug__:
            result = await loop.spawn(super().__iter__(), self.content,
                                      input_signal)
            if isinstance(result, str):
                return int(result)
            else:
                return result
        else:
            return await loop.spawn(super().__iter__(), self.content)
Exemple #5
0
class MnemonicKeyboard(ui.Widget):
    def __init__(self, prompt: str=''):
        self.prompt = prompt
        self.input = Input(ui.grid(1, n_x=4, n_y=4, cells_x=3), '', '')
        self.back = Button(ui.grid(0, n_x=4, n_y=4),
                           res.load(ui.ICON_BACK),
                           style=ui.BTN_CLEAR)
        self.keys = key_buttons(MNEMONIC_KEYS)
        self.pbutton = None  # pending key button
        self.pindex = 0  # index of current pending char in pbutton

    def render(self):
        if self.input.content:
            # content button and backspace
            self.input.render()
            self.back.render()
        else:
            # prompt
            display.bar(0, 8, 240, 60, ui.BG)
            display.text(20, 40, self.prompt, ui.BOLD, ui.GREY, ui.BG)
        # key buttons
        for btn in self.keys:
            btn.render()

    def touch(self, event, pos):
        content = self.input.content
        word = self.input.word

        if self.back.touch(event, pos) == BTN_CLICKED:
            # backspace, delete the last character of input
            self.edit(content[:-1])
            return

        if self.input.touch(event, pos) == BTN_CLICKED:
            # input press, either auto-complete or confirm
            if content == word:
                self.edit('')
                return content
            else:
                self.edit(word)
                return

        for btn in self.keys:
            if btn.touch(event, pos) == BTN_CLICKED:
                # key press, add new char to input or cycle the pending button
                if self.pbutton is btn:
                    index = (self.pindex + 1) % len(btn.content)
                    content = content[:-1] + btn.content[index]
                else:
                    index = 0
                    content += btn.content[0]
                self.edit(content, btn, index)
                return

    def edit(self, content, button=None, index=0):
        word = bip39.find_word(content) or ''
        mask = bip39.complete_word(content)

        self.pbutton = button
        self.pindex = index
        self.input.edit(content, word, button is not None)

        # enable or disable key buttons
        for btn in self.keys:
            if btn is button or compute_mask(btn.content) & mask:
                btn.enable()
            else:
                btn.disable()

    async def __iter__(self):
        timeout = loop.sleep(1000 * 1000 * 1)
        touch = loop.select(io.TOUCH)
        wait_timeout = loop.wait(touch, timeout)
        wait_touch = loop.wait(touch)
        content = None

        self.back.taint()
        self.input.taint()

        while content is None:
            self.render()
            if self.pbutton is not None:
                wait = wait_timeout
            else:
                wait = wait_touch
            result = await wait
            if touch in wait.finished:
                event, *pos = result
                content = self.touch(event, pos)
            else:
                if self.input.word:
                    # just reset the pending state
                    self.edit(self.input.content)
                else:
                    # invalid character, backspace it
                    self.edit(self.input.content[:-1])
        return content
Exemple #6
0
class PassphraseKeyboard(ui.Widget):
    def __init__(self, prompt, page=1):
        self.prompt = Prompt(prompt)
        self.page = page
        self.input = Input(ui.grid(0, n_x=1, n_y=6), '')
        self.back = Button(ui.grid(12),
                           res.load(ui.ICON_BACK),
                           style=ui.BTN_CLEAR)
        self.done = Button(ui.grid(14),
                           res.load(ui.ICON_CONFIRM),
                           style=ui.BTN_CONFIRM)
        self.keys = key_buttons(KEYBOARD_KEYS[self.page])
        self.pbutton = None  # pending key button
        self.pindex = 0  # index of current pending char in pbutton

    def render(self):
        # passphrase or prompt
        if self.input.content:
            self.input.render()
        else:
            self.prompt.render()
        render_scrollbar(self.page)
        # buttons
        self.back.render()
        self.done.render()
        for btn in self.keys:
            btn.render()

    def touch(self, event, pos):
        content = self.input.content
        if self.back.touch(event, pos) == BTN_CLICKED:
            if content:
                # backspace, delete the last character of input
                self.edit(content[:-1])
                return
            else:
                # cancel
                return CANCELLED
        if self.done.touch(event, pos) == BTN_CLICKED:
            # confirm button, return the content
            return content
        for btn in self.keys:
            if btn.touch(event, pos) == BTN_CLICKED:
                if isinstance(btn.content[0], str):
                    # key press, add new char to input or cycle the pending button
                    if self.pbutton is btn:
                        index = (self.pindex + 1) % len(btn.content)
                        content = content[:-1] + btn.content[index]
                    else:
                        index = 0
                        content += btn.content[0]
                else:
                    index = 0
                    content += ' '

                self.edit(content, btn, index)
                return

    def edit(self, content, button=None, index=0):
        if button and len(button.content) == 1:
            # one-letter buttons are never pending
            button = None
            index = 0
        self.pbutton = button
        self.pindex = index
        self.input.edit(content, button is not None)
        if content:
            self.back.enable()
        else:
            self.back.disable()
            self.prompt.taint()

    async def __iter__(self):
        self.edit(self.input.content)  # init button state
        while True:
            change = self.change_page()
            enter = self.enter_text()
            wait = loop.spawn(change, enter)
            result = await wait
            if enter in wait.finished:
                return result

    @ui.layout
    async def enter_text(self):
        timeout = loop.sleep(1000 * 1000 * 1)
        touch = loop.wait(io.TOUCH)
        wait_timeout = loop.spawn(touch, timeout)
        wait_touch = loop.spawn(touch)
        content = None
        while content is None:
            self.render()
            if self.pbutton is not None:
                wait = wait_timeout
            else:
                wait = wait_touch
            result = await wait
            if touch in wait.finished:
                event, *pos = result
                content = self.touch(event, pos)
            else:
                # disable the pending buttons
                self.edit(self.input.content)
        return content

    async def change_page(self):
        swipe = await Swipe(directions=SWIPE_HORIZONTAL)
        if swipe == SWIPE_LEFT:
            self.page = (self.page + 1) % len(KEYBOARD_KEYS)
        else:
            self.page = (self.page - 1) % len(KEYBOARD_KEYS)
        self.keys = key_buttons(KEYBOARD_KEYS[self.page])
        self.back.taint()
        self.done.taint()
        self.input.taint()
        self.prompt.taint()
Exemple #7
0
class KeyboardZooming(ui.Widget):
    def __init__(self, content='', uppercase=True):
        self.content = content
        self.uppercase = uppercase

        self.zoom_buttons = None
        self.key_buttons = key_buttons()
        self.bs_button = Button((240 - 35, 5, 30, 30),
                                res.load('trezor/res/pin_close.toig'),
                                normal_style=ui.BTN_CLEAR,
                                active_style=ui.BTN_CLEAR_ACTIVE)

    def render(self):
        self.render_input()
        if self.zoom_buttons:
            for btn in self.zoom_buttons:
                btn.render()
        else:
            for btn in self.key_buttons:
                btn.render()

    def render_input(self):
        if self.content:
            display.bar(0, 0, 200, 40, ui.BG)
        else:
            display.bar(0, 0, 240, 40, ui.BG)
        display.text(20, 30, self.content, ui.BOLD, ui.GREY, ui.BG)
        if self.content:
            self.bs_button.render()

    def touch(self, event, pos):
        if self.bs_button.touch(event, pos) == BTN_CLICKED:
            self.content = self.content[:-1]
            self.bs_button.taint()
            return
        if self.zoom_buttons:
            return self.touch_zoom(event, pos)
        else:
            return self.touch_keyboard(event, pos)

    def touch_zoom(self, event, pos):
        for btn in self.zoom_buttons:
            if btn.touch(event, pos) == BTN_CLICKED:
                self.content += btn.content
                self.zoom_buttons = None
                for b in self.key_buttons:
                    b.taint()
                self.bs_button.taint()
                break

    def touch_keyboard(self, event, pos):
        for btn in self.key_buttons:
            if btn.touch(event, pos) == BTN_CLICKED:
                self.zoom_buttons = zoom_buttons(btn.content, self.uppercase)
                for b in self.zoom_buttons:
                    b.taint()
                self.bs_button.taint()
                break

    def __iter__(self):
        timeout = loop.sleep(1000 * 1000 * 1)
        touch = loop.select(io.TOUCH)
        wait = loop.wait(touch, timeout)
        while True:
            self.render()
            result = yield wait
            if touch in wait.finished:
                event, *pos = result
                self.touch(event, pos)
            elif self.zoom_buttons:
                self.zoom_buttons = None
                for btn in self.key_buttons:
                    btn.taint()