mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-03 05:12:34 +00:00
refactor(core/rust/ui): avoid homescreen flicker during workflow restarts
[no changelog]
This commit is contained in:
parent
e76a394c4b
commit
b5d0c0eec9
@ -97,4 +97,5 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_notification;
|
MP_QSTR_notification;
|
||||||
MP_QSTR_notification_level;
|
MP_QSTR_notification_level;
|
||||||
MP_QSTR_bootscreen;
|
MP_QSTR_bootscreen;
|
||||||
|
MP_QSTR_skip_first_paint;
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,16 @@ impl<T> Child<T> {
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Do not draw on screen until an event requests paint. This is used by
|
||||||
|
/// homescreens to avoid flickerg when workflow restart happens.
|
||||||
|
pub fn skip_paint(&mut self) {
|
||||||
|
self.marked_for_paint = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn will_paint(&self) -> bool {
|
||||||
|
self.marked_for_paint
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Component for Child<T>
|
impl<T> Component for Child<T>
|
||||||
|
@ -70,8 +70,9 @@ use maybe_trace::MaybeTrace;
|
|||||||
pub trait ObjComponent: MaybeTrace {
|
pub trait ObjComponent: MaybeTrace {
|
||||||
fn obj_place(&mut self, bounds: Rect) -> Rect;
|
fn obj_place(&mut self, bounds: Rect) -> Rect;
|
||||||
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error>;
|
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error>;
|
||||||
fn obj_paint(&mut self);
|
fn obj_paint(&mut self) -> bool;
|
||||||
fn obj_bounds(&self, sink: &mut dyn FnMut(Rect));
|
fn obj_bounds(&self, sink: &mut dyn FnMut(Rect));
|
||||||
|
fn obj_skip_paint(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ObjComponent for Child<T>
|
impl<T> ObjComponent for Child<T>
|
||||||
@ -90,13 +91,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_paint(&mut self) {
|
fn obj_paint(&mut self) -> bool {
|
||||||
|
let will_paint = self.will_paint();
|
||||||
self.paint();
|
self.paint();
|
||||||
|
will_paint
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
fn obj_bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||||
self.bounds(sink)
|
self.bounds(sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn obj_skip_paint(&mut self) {
|
||||||
|
self.skip_paint()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `LayoutObj` is a GC-allocated object exported to MicroPython, with type
|
/// `LayoutObj` is a GC-allocated object exported to MicroPython, with type
|
||||||
@ -136,6 +143,13 @@ impl LayoutObj {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skip_first_paint(&self) {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
|
||||||
|
// SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`.
|
||||||
|
unsafe { Gc::as_mut(&mut inner.root) }.obj_skip_paint();
|
||||||
|
}
|
||||||
|
|
||||||
/// Timer callback is expected to be a callable object of the following
|
/// Timer callback is expected to be a callable object of the following
|
||||||
/// form: `def timer(token: int, deadline_in_ms: int)`.
|
/// form: `def timer(token: int, deadline_in_ms: int)`.
|
||||||
fn obj_set_timer_fn(&self, timer_fn: Obj) {
|
fn obj_set_timer_fn(&self, timer_fn: Obj) {
|
||||||
@ -183,8 +197,9 @@ impl LayoutObj {
|
|||||||
Ok(msg)
|
Ok(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a paint pass over the component tree.
|
/// Run a paint pass over the component tree. Returns true if any component
|
||||||
fn obj_paint_if_requested(&self) {
|
/// actually requested painting since last invocation of the function.
|
||||||
|
fn obj_paint_if_requested(&self) -> bool {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
|
||||||
// Place the root component on the screen in case it was previously requested.
|
// Place the root component on the screen in case it was previously requested.
|
||||||
@ -194,7 +209,7 @@ impl LayoutObj {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`.
|
// SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`.
|
||||||
unsafe { Gc::as_mut(&mut inner.root) }.obj_paint();
|
unsafe { Gc::as_mut(&mut inner.root) }.obj_paint()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a tracing pass over the component tree. Passed `callback` is called
|
/// Run a tracing pass over the component tree. Passed `callback` is called
|
||||||
@ -431,8 +446,8 @@ extern "C" fn ui_layout_timer(this: Obj, token: Obj) -> Obj {
|
|||||||
extern "C" fn ui_layout_paint(this: Obj) -> Obj {
|
extern "C" fn ui_layout_paint(this: Obj) -> Obj {
|
||||||
let block = || {
|
let block = || {
|
||||||
let this: Gc<LayoutObj> = this.try_into()?;
|
let this: Gc<LayoutObj> = this.try_into()?;
|
||||||
this.obj_paint_if_requested();
|
let painted = this.obj_paint_if_requested().into();
|
||||||
Ok(Obj::const_true())
|
Ok(painted)
|
||||||
};
|
};
|
||||||
unsafe { util::try_or_raise(block) }
|
unsafe { util::try_or_raise(block) }
|
||||||
}
|
}
|
||||||
|
@ -1011,9 +1011,13 @@ extern "C" fn new_show_homescreen(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
kwargs.get(Qstr::MP_QSTR_notification)?.try_into_option()?;
|
kwargs.get(Qstr::MP_QSTR_notification)?.try_into_option()?;
|
||||||
let notification_level: u32 = kwargs.get_or(Qstr::MP_QSTR_notification_level, 0)?;
|
let notification_level: u32 = kwargs.get_or(Qstr::MP_QSTR_notification_level, 0)?;
|
||||||
let hold: bool = kwargs.get(Qstr::MP_QSTR_hold)?.try_into()?;
|
let hold: bool = kwargs.get(Qstr::MP_QSTR_hold)?.try_into()?;
|
||||||
|
let skip_first_paint: bool = kwargs.get(Qstr::MP_QSTR_skip_first_paint)?.try_into()?;
|
||||||
|
|
||||||
let notification = notification.map(|w| (w, notification_level));
|
let notification = notification.map(|w| (w, notification_level));
|
||||||
let obj = LayoutObj::new(Homescreen::new(label, notification, hold))?;
|
let obj = LayoutObj::new(Homescreen::new(label, notification, hold))?;
|
||||||
|
if skip_first_paint {
|
||||||
|
obj.skip_first_paint();
|
||||||
|
}
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||||
@ -1023,8 +1027,12 @@ extern "C" fn new_show_lockscreen(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||||
let label: StrBuffer = kwargs.get(Qstr::MP_QSTR_label)?.try_into()?;
|
let label: StrBuffer = kwargs.get(Qstr::MP_QSTR_label)?.try_into()?;
|
||||||
let bootscreen: bool = kwargs.get(Qstr::MP_QSTR_bootscreen)?.try_into()?;
|
let bootscreen: bool = kwargs.get(Qstr::MP_QSTR_bootscreen)?.try_into()?;
|
||||||
|
let skip_first_paint: bool = kwargs.get(Qstr::MP_QSTR_skip_first_paint)?.try_into()?;
|
||||||
|
|
||||||
let obj = LayoutObj::new(Lockscreen::new(label, bootscreen))?;
|
let obj = LayoutObj::new(Lockscreen::new(label, bootscreen))?;
|
||||||
|
if skip_first_paint {
|
||||||
|
obj.skip_first_paint();
|
||||||
|
}
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||||
@ -1035,6 +1043,7 @@ extern "C" fn new_show_busyscreen(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||||
let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
||||||
let time_ms: u32 = kwargs.get(Qstr::MP_QSTR_time_ms)?.try_into()?;
|
let time_ms: u32 = kwargs.get(Qstr::MP_QSTR_time_ms)?.try_into()?;
|
||||||
|
let skip_first_paint: bool = kwargs.get(Qstr::MP_QSTR_skip_first_paint)?.try_into()?;
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::new(
|
let obj = LayoutObj::new(Frame::new(
|
||||||
title,
|
title,
|
||||||
@ -1047,6 +1056,9 @@ extern "C" fn new_show_busyscreen(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
))?;
|
))?;
|
||||||
|
if skip_first_paint {
|
||||||
|
obj.skip_first_paint();
|
||||||
|
}
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||||
@ -1337,6 +1349,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// hold: bool,
|
/// hold: bool,
|
||||||
/// notification: str | None,
|
/// notification: str | None,
|
||||||
/// notification_level: int = 0,
|
/// notification_level: int = 0,
|
||||||
|
/// skip_first_paint: bool,
|
||||||
/// ) -> trezorui2.CANCELLED:
|
/// ) -> trezorui2.CANCELLED:
|
||||||
/// """Idle homescreen."""
|
/// """Idle homescreen."""
|
||||||
Qstr::MP_QSTR_show_homescreen => obj_fn_kw!(0, new_show_homescreen).as_obj(),
|
Qstr::MP_QSTR_show_homescreen => obj_fn_kw!(0, new_show_homescreen).as_obj(),
|
||||||
@ -1345,6 +1358,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// *,
|
/// *,
|
||||||
/// label: str,
|
/// label: str,
|
||||||
/// bootscreen: bool,
|
/// bootscreen: bool,
|
||||||
|
/// skip_first_paint: bool,
|
||||||
/// ) -> trezorui2.CANCELLED:
|
/// ) -> trezorui2.CANCELLED:
|
||||||
/// """Homescreen for locked device."""
|
/// """Homescreen for locked device."""
|
||||||
Qstr::MP_QSTR_show_lockscreen => obj_fn_kw!(0, new_show_lockscreen).as_obj(),
|
Qstr::MP_QSTR_show_lockscreen => obj_fn_kw!(0, new_show_lockscreen).as_obj(),
|
||||||
@ -1354,6 +1368,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// title: str,
|
/// title: str,
|
||||||
/// description: str,
|
/// description: str,
|
||||||
/// time_ms: int,
|
/// time_ms: int,
|
||||||
|
/// skip_first_paint: bool,
|
||||||
/// ) -> trezorui2.CANCELLED:
|
/// ) -> trezorui2.CANCELLED:
|
||||||
/// """Homescreen used for indicating coinjoin in progress."""
|
/// """Homescreen used for indicating coinjoin in progress."""
|
||||||
Qstr::MP_QSTR_show_busyscreen => obj_fn_kw!(0, new_show_busyscreen).as_obj(),
|
Qstr::MP_QSTR_show_busyscreen => obj_fn_kw!(0, new_show_busyscreen).as_obj(),
|
||||||
|
@ -357,6 +357,7 @@ def show_homescreen(
|
|||||||
hold: bool,
|
hold: bool,
|
||||||
notification: str | None,
|
notification: str | None,
|
||||||
notification_level: int = 0,
|
notification_level: int = 0,
|
||||||
|
skip_first_paint: bool,
|
||||||
) -> trezorui2.CANCELLED:
|
) -> trezorui2.CANCELLED:
|
||||||
"""Idle homescreen."""
|
"""Idle homescreen."""
|
||||||
|
|
||||||
@ -366,6 +367,7 @@ def show_lockscreen(
|
|||||||
*,
|
*,
|
||||||
label: str,
|
label: str,
|
||||||
bootscreen: bool,
|
bootscreen: bool,
|
||||||
|
skip_first_paint: bool,
|
||||||
) -> trezorui2.CANCELLED:
|
) -> trezorui2.CANCELLED:
|
||||||
"""Homescreen for locked device."""
|
"""Homescreen for locked device."""
|
||||||
|
|
||||||
@ -376,5 +378,6 @@ def show_busyscreen(
|
|||||||
title: str,
|
title: str,
|
||||||
description: str,
|
description: str,
|
||||||
time_ms: int,
|
time_ms: int,
|
||||||
|
skip_first_paint: bool,
|
||||||
) -> trezorui2.CANCELLED:
|
) -> trezorui2.CANCELLED:
|
||||||
"""Homescreen used for indicating coinjoin in progress."""
|
"""Homescreen used for indicating coinjoin in progress."""
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from ubinascii import hexlify
|
from ubinascii import hexlify
|
||||||
|
|
||||||
|
import storage.cache
|
||||||
from trezor import io, log, loop, ui, wire, workflow
|
from trezor import io, log, loop, ui, wire, workflow
|
||||||
from trezor.enums import ButtonRequestType
|
from trezor.enums import ButtonRequestType
|
||||||
|
|
||||||
@ -32,6 +33,11 @@ class _RustLayout(ui.Layout):
|
|||||||
msg = self.layout.request_complete_repaint()
|
msg = self.layout.request_complete_repaint()
|
||||||
assert msg is None
|
assert msg is None
|
||||||
|
|
||||||
|
def _paint(self) -> None:
|
||||||
|
painted = self.layout.paint()
|
||||||
|
if storage.cache.homescreen_shown is not None and painted:
|
||||||
|
storage.cache.homescreen_shown = None
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
|
|
||||||
def create_tasks(self) -> tuple[loop.AwaitableTask, ...]:
|
def create_tasks(self) -> tuple[loop.AwaitableTask, ...]:
|
||||||
@ -81,7 +87,7 @@ class _RustLayout(ui.Layout):
|
|||||||
(io.TOUCH_END, orig_x + 2 * off_x, orig_y + 2 * off_y),
|
(io.TOUCH_END, orig_x + 2 * off_x, orig_y + 2 * off_y),
|
||||||
):
|
):
|
||||||
msg = self.layout.touch_event(event, x, y)
|
msg = self.layout.touch_event(event, x, y)
|
||||||
self.layout.paint()
|
self._paint()
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
raise ui.Result(msg)
|
raise ui.Result(msg)
|
||||||
|
|
||||||
@ -111,7 +117,7 @@ class _RustLayout(ui.Layout):
|
|||||||
def create_tasks(self) -> tuple[loop.AwaitableTask, ...]:
|
def create_tasks(self) -> tuple[loop.AwaitableTask, ...]:
|
||||||
return self.handle_timers(), self.handle_input_and_rendering()
|
return self.handle_timers(), self.handle_input_and_rendering()
|
||||||
|
|
||||||
def _before_render(self) -> None:
|
def _first_paint(self) -> None:
|
||||||
# Clear the screen of any leftovers.
|
# Clear the screen of any leftovers.
|
||||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||||
ui.display.clear()
|
ui.display.clear()
|
||||||
@ -127,11 +133,11 @@ class _RustLayout(ui.Layout):
|
|||||||
|
|
||||||
# Turn the brightness on again.
|
# Turn the brightness on again.
|
||||||
ui.backlight_fade(self.BACKLIGHT_LEVEL)
|
ui.backlight_fade(self.BACKLIGHT_LEVEL)
|
||||||
|
self._paint()
|
||||||
|
|
||||||
def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
|
def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
|
||||||
touch = loop.wait(io.TOUCH)
|
touch = loop.wait(io.TOUCH)
|
||||||
self._before_render()
|
self._first_paint()
|
||||||
self.layout.paint()
|
|
||||||
# self.layout.bounds()
|
# self.layout.bounds()
|
||||||
while True:
|
while True:
|
||||||
# Using `yield` instead of `await` to avoid allocations.
|
# Using `yield` instead of `await` to avoid allocations.
|
||||||
@ -140,7 +146,7 @@ class _RustLayout(ui.Layout):
|
|||||||
msg = None
|
msg = None
|
||||||
if event in (io.TOUCH_START, io.TOUCH_MOVE, io.TOUCH_END):
|
if event in (io.TOUCH_START, io.TOUCH_MOVE, io.TOUCH_END):
|
||||||
msg = self.layout.touch_event(event, x, y)
|
msg = self.layout.touch_event(event, x, y)
|
||||||
self.layout.paint()
|
self._paint()
|
||||||
# self.layout.bounds()
|
# self.layout.bounds()
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
raise ui.Result(msg)
|
raise ui.Result(msg)
|
||||||
@ -150,7 +156,7 @@ class _RustLayout(ui.Layout):
|
|||||||
# Using `yield` instead of `await` to avoid allocations.
|
# Using `yield` instead of `await` to avoid allocations.
|
||||||
token = yield self.timer
|
token = yield self.timer
|
||||||
msg = self.layout.timer(token)
|
msg = self.layout.timer(token)
|
||||||
self.layout.paint()
|
self._paint()
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
raise ui.Result(msg)
|
raise ui.Result(msg)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ from typing import Any, Tuple
|
|||||||
|
|
||||||
import storage.cache
|
import storage.cache
|
||||||
import storage.device
|
import storage.device
|
||||||
from trezor import io, loop, ui
|
from trezor import io, loop, ui, utils
|
||||||
|
|
||||||
import trezorui2
|
import trezorui2
|
||||||
from apps.base import set_homescreen
|
from apps.base import set_homescreen
|
||||||
@ -26,6 +26,21 @@ class HomescreenBase(_RustLayout):
|
|||||||
storage.cache.homescreen_shown = None
|
storage.cache.homescreen_shown = None
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def _first_paint(self) -> None:
|
||||||
|
if storage.cache.homescreen_shown is not self.RENDER_INDICATOR:
|
||||||
|
super()._first_paint()
|
||||||
|
storage.cache.homescreen_shown = self.RENDER_INDICATOR
|
||||||
|
|
||||||
|
# - RENDER_INDICATOR is set -> USB warning is not displayed
|
||||||
|
# - RENDER_INDICATOR is not set -> initially homescreen does not display warning
|
||||||
|
# - usb_checker_task only handles state changes
|
||||||
|
# Here we need to handle the case when homescreen is started with USB disconnected.
|
||||||
|
if not utils.usb_data_connected():
|
||||||
|
msg = self.layout.usb_event(False)
|
||||||
|
self._paint()
|
||||||
|
if msg is not None:
|
||||||
|
raise ui.Result(msg)
|
||||||
|
|
||||||
|
|
||||||
class Homescreen(HomescreenBase):
|
class Homescreen(HomescreenBase):
|
||||||
RENDER_INDICATOR = storage.cache.HOMESCREEN_ON
|
RENDER_INDICATOR = storage.cache.HOMESCREEN_ON
|
||||||
@ -45,12 +60,14 @@ class Homescreen(HomescreenBase):
|
|||||||
elif notification_is_error:
|
elif notification_is_error:
|
||||||
level = 0
|
level = 0
|
||||||
|
|
||||||
|
skip = storage.cache.homescreen_shown is self.RENDER_INDICATOR
|
||||||
super().__init__(
|
super().__init__(
|
||||||
layout=trezorui2.show_homescreen(
|
layout=trezorui2.show_homescreen(
|
||||||
label=label or "My Trezor",
|
label=label or "My Trezor",
|
||||||
notification=notification,
|
notification=notification,
|
||||||
notification_level=level,
|
notification_level=level,
|
||||||
hold=hold_to_lock,
|
hold=hold_to_lock,
|
||||||
|
skip_first_paint=skip,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -81,10 +98,14 @@ class Lockscreen(HomescreenBase):
|
|||||||
if bootscreen:
|
if bootscreen:
|
||||||
self.BACKLIGHT_LEVEL = ui.BACKLIGHT_NORMAL
|
self.BACKLIGHT_LEVEL = ui.BACKLIGHT_NORMAL
|
||||||
|
|
||||||
|
skip = (
|
||||||
|
not bootscreen and storage.cache.homescreen_shown is self.RENDER_INDICATOR
|
||||||
|
)
|
||||||
super().__init__(
|
super().__init__(
|
||||||
layout=trezorui2.show_lockscreen(
|
layout=trezorui2.show_lockscreen(
|
||||||
label=label or "My Trezor",
|
label=label or "My Trezor",
|
||||||
bootscreen=bootscreen,
|
bootscreen=bootscreen,
|
||||||
|
skip_first_paint=skip,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -99,11 +120,13 @@ class Busyscreen(HomescreenBase):
|
|||||||
RENDER_INDICATOR = storage.cache.BUSYSCREEN_ON
|
RENDER_INDICATOR = storage.cache.BUSYSCREEN_ON
|
||||||
|
|
||||||
def __init__(self, delay_ms: int) -> None:
|
def __init__(self, delay_ms: int) -> None:
|
||||||
|
skip = storage.cache.homescreen_shown is self.RENDER_INDICATOR
|
||||||
super().__init__(
|
super().__init__(
|
||||||
layout=trezorui2.show_busyscreen(
|
layout=trezorui2.show_busyscreen(
|
||||||
title="PLEASE WAIT",
|
title="PLEASE WAIT",
|
||||||
description="CoinJoin in progress.\n\nDo not disconnect your\nTrezor.",
|
description="CoinJoin in progress.\n\nDo not disconnect your\nTrezor.",
|
||||||
time_ms=delay_ms,
|
time_ms=delay_ms,
|
||||||
|
skip_first_paint=skip,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user