From 0637987c09a8cbf138fd6637bc9aa4583b348ab0 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Tue, 27 Sep 2016 15:32:12 +0200 Subject: [PATCH] change wipe_device to use long-press confirm --- src/apps/management/confirm.py | 19 ++++ src/apps/management/layout_wipe_device.py | 4 +- src/trezor/ui/confirm.py | 107 +++++++++++++++++++++- 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/apps/management/confirm.py b/src/apps/management/confirm.py index 62da9da5e..8332aab4a 100644 --- a/src/apps/management/confirm.py +++ b/src/apps/management/confirm.py @@ -18,6 +18,25 @@ async def confirm(session_id, content=None, code=None, **kwargs): return await dialog == CONFIRMED +@unimport +async def hold_to_confirm(session_id, code=None): + from trezor.ui.button import Button, CONFIRM_BUTTON, CONFIRM_BUTTON_ACTIVE + from trezor.ui.confirm import HoldToConfirmDialog, CONFIRMED + from trezor.messages.ButtonRequest import ButtonRequest + from trezor.messages.ButtonRequestType import Other + from trezor.messages.wire_types import ButtonAck + + button = Button((0, 240 - 48, 240, 48), 'Hold to confirm', + normal_style=CONFIRM_BUTTON, + active_style=CONFIRM_BUTTON_ACTIVE) + dialog = HoldToConfirmDialog(button) + + if code is None: + code = Other + await wire.reply_message(session_id, ButtonRequest(code=code), ButtonAck) + return await dialog == CONFIRMED + + @unimport async def require_confirm(*args, **kwargs): from trezor.messages.FailureType import ActionCancelled diff --git a/src/apps/management/layout_wipe_device.py b/src/apps/management/layout_wipe_device.py index 123ed9eab..829dd61cf 100644 --- a/src/apps/management/layout_wipe_device.py +++ b/src/apps/management/layout_wipe_device.py @@ -5,7 +5,7 @@ from trezor.utils import unimport @unimport async def layout_wipe_device(message, session_id): from trezor.messages.Success import Success - from .confirm import require_confirm + from .confirm import hold_to_confirm from .storage import clear_storage ui.clear() @@ -16,7 +16,7 @@ async def layout_wipe_device(message, session_id): ui.display.text(10, 164, 'All data will be lost.', ui.NORMAL, ui.WHITE, ui.BLACK) - await require_confirm(session_id) + await hold_to_confirm(session_id) clear_storage(session_id) diff --git a/src/trezor/ui/confirm.py b/src/trezor/ui/confirm.py index 014882ac2..dea98164a 100644 --- a/src/trezor/ui/confirm.py +++ b/src/trezor/ui/confirm.py @@ -1,7 +1,8 @@ -from .button import Button, BTN_CLICKED +import utime +from .button import Button, BTN_CLICKED, BTN_STARTED from .button import CONFIRM_BUTTON, CONFIRM_BUTTON_ACTIVE from .button import CANCEL_BUTTON, CANCEL_BUTTON_ACTIVE -from trezor import loop +from trezor import loop, ui CONFIRMED = const(1) @@ -40,3 +41,105 @@ class ConfirmDialog(): result = self.send(event, pos) if result is not None: return result + + +DEFAULT_LOADER = { + 'bg-color': ui.BLACK, + 'fg-color': ui.WHITE, + 'icon': None, + 'icon-fg-color': None, +} +DEFAULT_LOADER_ACTIVE = { + 'bg-color': ui.BLACK, + 'fg-color': ui.LIGHT_GREEN, + 'icon': None, + 'icon-fg-color': None, +} + +LOADER_MSEC = const(1000) + + +class Loader(): + + def __init__(self, normal_style=None, active_style=None): + self.start_ticks_ms = None + self.normal_style = normal_style or DEFAULT_LOADER + self.active_style = active_style or DEFAULT_LOADER_ACTIVE + + def start(self): + self.start_ticks_ms = utime.ticks_ms() + + def stop(self): + ticks_diff = utime.ticks_ms() - self.start_ticks_ms + self.start_ticks_ms = None + return ticks_diff >= LOADER_MSEC + + def render(self): + if self.start_ticks_ms is None: + return False + + progress = min(utime.ticks_ms() - self.start_ticks_ms, LOADER_MSEC) + if progress == LOADER_MSEC: + style = self.active_style + else: + style = self.normal_style + + if style['icon'] is None: + ui.display.loader(progress, style['fg-color'], style['bg-color']) + elif style['icon-fg-color'] is None: + ui.display.loader( + progress, style['fg-color'], style['bg-color'], style['icon']) + else: + ui.display.loader( + progress, style['fg-color'], style['bg-color'], style['icon'], style['icon-fg-color']) + + return True + + +class HoldToConfirmDialog(): + + def __init__(self, button, content=None, *args, **kwargs): + self.button = button + self.content = content + self.loader = Loader(*args, **kwargs) + + def render(self): + if not self.loader.render(): + if self.content is not None: + self.content.render() + else: + ui.display.bar(0, 0, 240, 240 - 48, ui.BLACK) + self.button.render() + + def send(self, event, pos): + if self.content is not None: + self.content.send(pos) + button = self.button + was_started = button.state & BTN_STARTED + button.send(event, pos) + is_started = button.state & BTN_STARTED + if is_started: + if not was_started: + self.loader.start() + else: + if was_started: + if self.loader.stop(): + return CONFIRMED + return None + + async def __iter__(self): + await loop.Wait([self._render_loop(), + self._event_loop()]) + + def _render_loop(self): + RENDER_DELAY = const(1000000 // 60) + while True: + self.render() + yield loop.Sleep(RENDER_DELAY) + + def _event_loop(self): + while True: + event, *pos = yield loop.Select(loop.TOUCH) + result = self.send(event, pos) + if result is not None: + return result