mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-26 16:18:22 +00:00
fix(core/ui): coinjoin layouts style update
[no changelog]
This commit is contained in:
parent
77d8af1322
commit
08cad2f909
Binary file not shown.
Before Width: | Height: | Size: 209 B After Width: | Height: | Size: 378 B |
@ -50,7 +50,6 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_request_slip39;
|
||||
MP_QSTR_select_word;
|
||||
MP_QSTR_select_word_count;
|
||||
MP_QSTR_show_busyscreen;
|
||||
MP_QSTR_show_group_share_success;
|
||||
MP_QSTR_show_homescreen;
|
||||
MP_QSTR_show_lockscreen;
|
||||
@ -58,6 +57,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_show_remaining_shares;
|
||||
MP_QSTR_show_share_words;
|
||||
MP_QSTR_show_progress;
|
||||
MP_QSTR_show_progress_coinjoin;
|
||||
MP_QSTR_show_address_details;
|
||||
|
||||
MP_QSTR_attach_timer_fn;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display::Font,
|
||||
geometry::{Alignment, Offset, Rect},
|
||||
geometry::{Alignment, Insets, Offset, Rect},
|
||||
};
|
||||
|
||||
use super::{text::TextStyle, TextLayout};
|
||||
@ -9,6 +9,7 @@ use super::{text::TextStyle, TextLayout};
|
||||
pub struct Label<T> {
|
||||
text: T,
|
||||
layout: TextLayout,
|
||||
vertical: Alignment,
|
||||
}
|
||||
|
||||
impl<T> Label<T>
|
||||
@ -19,6 +20,7 @@ where
|
||||
Self {
|
||||
text,
|
||||
layout: TextLayout::new(style).with_align(align),
|
||||
vertical: Alignment::Start,
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +36,11 @@ where
|
||||
Self::new(text, Alignment::Center, style)
|
||||
}
|
||||
|
||||
pub fn vertically_aligned(mut self, align: Alignment) -> Self {
|
||||
self.vertical = align;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn text(&self) -> &T {
|
||||
&self.text
|
||||
}
|
||||
@ -68,7 +75,13 @@ where
|
||||
.with_bounds(bounds)
|
||||
.fit_text(self.text.as_ref())
|
||||
.height();
|
||||
self.layout = self.layout.with_bounds(bounds.with_height(height));
|
||||
let diff = bounds.height() - height;
|
||||
let insets = match self.vertical {
|
||||
Alignment::Start => Insets::bottom(diff),
|
||||
Alignment::Center => Insets::new(diff / 2, 0, diff / 2 + diff % 2, 0),
|
||||
Alignment::End => Insets::top(diff),
|
||||
};
|
||||
self.layout.bounds = bounds.inset(insets);
|
||||
self.layout.bounds
|
||||
}
|
||||
|
||||
|
@ -67,3 +67,8 @@ pub fn jpeg_painter<'a>(
|
||||
let f = move |area: Rect| display::tjpgd::jpeg(image(), area.center() - off, scale);
|
||||
Painter::new(f)
|
||||
}
|
||||
|
||||
pub fn rect_painter(fg: display::Color, bg: display::Color) -> Painter<impl FnMut(Rect)> {
|
||||
let f = move |area: Rect| display::rect_fill_rounded(area, fg, bg, 2);
|
||||
Painter::new(f)
|
||||
}
|
||||
|
@ -214,13 +214,21 @@ impl<T, U> Split<T, U> {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn vertical(size: i16, spacing: i16, first: T, second: U) -> Self {
|
||||
pub const fn left(size: i16, spacing: i16, first: T, second: U) -> Self {
|
||||
Self::new(Axis::Vertical, size, spacing, first, second)
|
||||
}
|
||||
|
||||
pub const fn horizontal(size: i16, spacing: i16, first: T, second: U) -> Self {
|
||||
pub const fn right(size: i16, spacing: i16, first: T, second: U) -> Self {
|
||||
Self::new(Axis::Vertical, -size, spacing, first, second)
|
||||
}
|
||||
|
||||
pub const fn top(size: i16, spacing: i16, first: T, second: U) -> Self {
|
||||
Self::new(Axis::Horizontal, size, spacing, first, second)
|
||||
}
|
||||
|
||||
pub const fn bottom(size: i16, spacing: i16, first: T, second: U) -> Self {
|
||||
Self::new(Axis::Horizontal, -size, spacing, first, second)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, T, U> Component for Split<T, U>
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::ui::{
|
||||
constant, display,
|
||||
display::Color,
|
||||
constant,
|
||||
constant::{screen, LOADER_INNER, LOADER_OUTER},
|
||||
display,
|
||||
display::{toif::Icon, Color},
|
||||
geometry::{Offset, Point, Rect},
|
||||
};
|
||||
|
||||
@ -10,25 +12,35 @@ use crate::trezorhal::{
|
||||
dma2d::{dma2d_setup_4bpp_over_4bpp, dma2d_start_blend, dma2d_wait_for_transfer},
|
||||
};
|
||||
|
||||
use crate::ui::{
|
||||
constant::{screen, LOADER_OUTER},
|
||||
display::toif::Icon,
|
||||
};
|
||||
|
||||
const LOADER_SIZE: i32 = (LOADER_OUTER * 2.0) as i32;
|
||||
|
||||
const OUTER: f32 = constant::LOADER_OUTER;
|
||||
const INNER: f32 = constant::LOADER_INNER;
|
||||
const ICON_MAX_SIZE: i16 = constant::LOADER_ICON_MAX_SIZE;
|
||||
|
||||
const IN_INNER_ANTI: i32 = ((INNER - 0.5) * (INNER - 0.5)) as i32;
|
||||
const INNER_MIN: i32 = ((INNER + 0.5) * (INNER + 0.5)) as i32;
|
||||
const INNER_MAX: i32 = ((INNER + 1.5) * (INNER + 1.5)) as i32;
|
||||
const INNER_OUTER_ANTI: i32 = ((INNER + 2.5) * (INNER + 2.5)) as i32;
|
||||
const OUTER_OUT_ANTI: i32 = ((OUTER - 1.5) * (OUTER - 1.5)) as i32;
|
||||
const OUTER_MAX: i32 = ((OUTER - 0.5) * (OUTER - 0.5)) as i32;
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LoaderDimensions {
|
||||
in_inner_anti: i32,
|
||||
inner_min: i32,
|
||||
inner_max: i32,
|
||||
inner_outer_anti: i32,
|
||||
outer_out_anti: i32,
|
||||
outer_max: i32,
|
||||
}
|
||||
|
||||
impl LoaderDimensions {
|
||||
pub fn new(outer: i16, inner: i16) -> Self {
|
||||
let outer: f32 = outer.into();
|
||||
let inner: f32 = inner.into();
|
||||
Self {
|
||||
in_inner_anti: ((inner - 0.5) * (inner - 0.5)) as i32,
|
||||
inner_min: ((inner + 0.5) * (inner + 0.5)) as i32,
|
||||
inner_max: ((inner + 1.5) * (inner + 1.5)) as i32,
|
||||
inner_outer_anti: ((inner + 2.5) * (inner + 2.5)) as i32,
|
||||
outer_out_anti: ((outer - 1.5) * (outer - 1.5)) as i32,
|
||||
outer_max: ((outer - 0.5) * (outer - 0.5)) as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loader_circular_uncompress(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
@ -36,20 +48,42 @@ pub fn loader_circular_uncompress(
|
||||
indeterminate: bool,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
const ICON_MAX_SIZE: i16 = constant::LOADER_ICON_MAX_SIZE;
|
||||
|
||||
if let Some((icon, color)) = icon {
|
||||
let toif_size = icon.toif.size();
|
||||
if toif_size.x <= ICON_MAX_SIZE && toif_size.y <= ICON_MAX_SIZE {
|
||||
let mut icon_data = [0_u8; ((ICON_MAX_SIZE * ICON_MAX_SIZE) / 2) as usize];
|
||||
icon.toif.uncompress(&mut icon_data);
|
||||
let i = Some((icon_data.as_ref(), color, toif_size));
|
||||
loader_rust(y_offset, fg_color, bg_color, progress, indeterminate, i);
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
i,
|
||||
);
|
||||
} else {
|
||||
loader_rust(y_offset, fg_color, bg_color, progress, indeterminate, None);
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
None,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
loader_rust(y_offset, fg_color, bg_color, progress, indeterminate, None);
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +94,15 @@ pub fn loader_circular(
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
loader_circular_uncompress(y_offset, fg_color, bg_color, progress, false, icon);
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
false,
|
||||
icon,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn loader_circular_indeterminate(
|
||||
@ -70,7 +112,15 @@ pub fn loader_circular_indeterminate(
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
loader_circular_uncompress(y_offset, fg_color, bg_color, progress, true, icon);
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
true,
|
||||
icon,
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -78,8 +128,8 @@ fn get_loader_vectors(indeterminate: bool, progress: u16) -> (Point, Point) {
|
||||
let (start_progress, end_progress) = if indeterminate {
|
||||
const LOADER_INDETERMINATE_WIDTH: u16 = 100;
|
||||
(
|
||||
progress - LOADER_INDETERMINATE_WIDTH,
|
||||
progress + LOADER_INDETERMINATE_WIDTH,
|
||||
(progress + 1000 - LOADER_INDETERMINATE_WIDTH) % 1000,
|
||||
(progress + LOADER_INDETERMINATE_WIDTH) % 1000,
|
||||
)
|
||||
} else {
|
||||
(0, progress)
|
||||
@ -114,12 +164,12 @@ fn loader_get_pixel_color_idx(
|
||||
inverted: bool,
|
||||
end_vector: Point,
|
||||
n_start: Point,
|
||||
x_c: i16,
|
||||
y_c: i16,
|
||||
c: Point,
|
||||
center: Point,
|
||||
dim: LoaderDimensions,
|
||||
) -> u8 {
|
||||
let y_p = -(y_c - center.y);
|
||||
let x_p = x_c - center.x;
|
||||
let y_p = -(c.y - center.y);
|
||||
let x_p = c.x - center.x;
|
||||
|
||||
let vx = Point::new(x_p, y_p);
|
||||
let n_vx = Point::new(-y_p, x_p);
|
||||
@ -142,31 +192,31 @@ fn loader_get_pixel_color_idx(
|
||||
// - r_inner)/(r_outer-r_inner) is negligible
|
||||
if show_all || included {
|
||||
//active part
|
||||
if d <= IN_INNER_ANTI {
|
||||
if d <= dim.in_inner_anti {
|
||||
0
|
||||
} else if d <= INNER_MIN {
|
||||
((15 * (d - IN_INNER_ANTI)) / (INNER_MIN - IN_INNER_ANTI)) as u8
|
||||
} else if d <= OUTER_OUT_ANTI {
|
||||
} else if d <= dim.inner_min {
|
||||
((15 * (d - dim.in_inner_anti)) / (dim.inner_min - dim.in_inner_anti)) as u8
|
||||
} else if d <= dim.outer_out_anti {
|
||||
15
|
||||
} else if d <= OUTER_MAX {
|
||||
(15 - ((15 * (d - OUTER_OUT_ANTI)) / (OUTER_MAX - OUTER_OUT_ANTI))) as u8
|
||||
} else if d <= dim.outer_max {
|
||||
(15 - ((15 * (d - dim.outer_out_anti)) / (dim.outer_max - dim.outer_out_anti))) as u8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
//inactive part
|
||||
if d <= IN_INNER_ANTI {
|
||||
if d <= dim.in_inner_anti {
|
||||
0
|
||||
} else if d <= INNER_MIN {
|
||||
((15 * (d - IN_INNER_ANTI)) / (INNER_MIN - IN_INNER_ANTI)) as u8
|
||||
} else if d <= INNER_MAX {
|
||||
} else if d <= dim.inner_min {
|
||||
((15 * (d - dim.in_inner_anti)) / (dim.inner_min - dim.in_inner_anti)) as u8
|
||||
} else if d <= dim.inner_max {
|
||||
15
|
||||
} else if d <= INNER_OUTER_ANTI {
|
||||
(15 - ((10 * (d - INNER_MAX)) / (INNER_OUTER_ANTI - INNER_MAX))) as u8
|
||||
} else if d <= OUTER_OUT_ANTI {
|
||||
} else if d <= dim.inner_outer_anti {
|
||||
(15 - ((10 * (d - dim.inner_max)) / (dim.inner_outer_anti - dim.inner_max))) as u8
|
||||
} else if d <= dim.outer_out_anti {
|
||||
5
|
||||
} else if d <= OUTER_MAX {
|
||||
5 - ((5 * (d - OUTER_OUT_ANTI)) / (OUTER_MAX - OUTER_OUT_ANTI)) as u8
|
||||
} else if d <= dim.outer_max {
|
||||
5 - ((5 * (d - dim.outer_out_anti)) / (dim.outer_max - dim.outer_out_anti)) as u8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@ -175,6 +225,7 @@ fn loader_get_pixel_color_idx(
|
||||
|
||||
#[cfg(not(feature = "dma2d"))]
|
||||
pub fn loader_rust(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
@ -225,7 +276,7 @@ pub fn loader_rust(
|
||||
if use_icon && icon_area_clamped.contains(p) {
|
||||
let x = x_c - center.x;
|
||||
let y = y_c - center.y;
|
||||
if (x as i32 * x as i32 + y as i32 * y as i32) <= IN_INNER_ANTI {
|
||||
if (x as i32 * x as i32 + y as i32 * y as i32) <= dim.in_inner_anti {
|
||||
let x_i = x_c - icon_area.x0;
|
||||
let y_i = y_c - icon_area.y0;
|
||||
|
||||
@ -241,7 +292,13 @@ pub fn loader_rust(
|
||||
|
||||
if clamped.contains(p) && !icon_pixel {
|
||||
let pix_c_idx = loader_get_pixel_color_idx(
|
||||
show_all, inverted, end_vector, n_start, x_c, y_c, center,
|
||||
show_all,
|
||||
inverted,
|
||||
end_vector,
|
||||
n_start,
|
||||
Point::new(x_c, y_c),
|
||||
center,
|
||||
dim,
|
||||
);
|
||||
underlying_color = colortable[pix_c_idx as usize];
|
||||
}
|
||||
@ -255,6 +312,7 @@ pub fn loader_rust(
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
pub fn loader_rust(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
@ -341,7 +399,13 @@ pub fn loader_rust(
|
||||
|
||||
let pix_c_idx = if clamped.contains(p) {
|
||||
loader_get_pixel_color_idx(
|
||||
show_all, inverted, end_vector, n_start, x_c, y_c, center,
|
||||
show_all,
|
||||
inverted,
|
||||
end_vector,
|
||||
n_start,
|
||||
Point::new(x_c, y_c),
|
||||
center,
|
||||
dim,
|
||||
)
|
||||
} else {
|
||||
0
|
||||
|
@ -9,6 +9,9 @@ use core::slice::from_raw_parts;
|
||||
use crate::ui::display::loader::circular::{
|
||||
loader_circular as determinate, loader_circular_indeterminate as indeterminate,
|
||||
};
|
||||
#[cfg(feature = "model_tt")]
|
||||
pub use crate::ui::display::loader::circular::{loader_circular_uncompress, LoaderDimensions};
|
||||
|
||||
#[cfg(not(feature = "model_tt"))]
|
||||
use crate::ui::display::loader::rectangular::loader_rectangular as determinate;
|
||||
#[cfg(not(feature = "model_tt"))]
|
||||
|
@ -5,8 +5,8 @@ pub const HEIGHT: i16 = 128;
|
||||
pub const LINE_SPACE: i16 = 1;
|
||||
pub const FONT_BPP: i16 = 1;
|
||||
|
||||
pub const LOADER_OUTER: f32 = 32_f32;
|
||||
pub const LOADER_INNER: f32 = 18_f32;
|
||||
pub const LOADER_OUTER: i32 = 32;
|
||||
pub const LOADER_INNER: i32 = 18;
|
||||
pub const LOADER_ICON_MAX_SIZE: i16 = 8;
|
||||
|
||||
pub const BACKLIGHT_NORMAL: i32 = 150;
|
||||
|
@ -391,7 +391,7 @@ impl<T> Button<T> {
|
||||
} else {
|
||||
0
|
||||
};
|
||||
theme::button_bar(Split::vertical(
|
||||
theme::button_bar(Split::left(
|
||||
width,
|
||||
theme::BUTTON_SPACING,
|
||||
left.map(|msg| {
|
||||
@ -456,11 +456,11 @@ impl<T> Button<T> {
|
||||
});
|
||||
let total_height = theme::BUTTON_HEIGHT + theme::BUTTON_SPACING + theme::INFO_BUTTON_HEIGHT;
|
||||
FixedHeightBar::bottom(
|
||||
Split::horizontal(
|
||||
Split::top(
|
||||
theme::INFO_BUTTON_HEIGHT,
|
||||
theme::BUTTON_SPACING,
|
||||
top,
|
||||
Split::vertical(theme::BUTTON_WIDTH, theme::BUTTON_SPACING, left, right),
|
||||
Split::left(theme::BUTTON_WIDTH, theme::BUTTON_SPACING, left, right),
|
||||
),
|
||||
total_height,
|
||||
)
|
||||
@ -488,11 +488,11 @@ impl<T> Button<T> {
|
||||
let [top, middle, bottom] = words;
|
||||
let total_height = 3 * theme::BUTTON_HEIGHT + 2 * theme::BUTTON_SPACING;
|
||||
FixedHeightBar::bottom(
|
||||
Split::horizontal(
|
||||
Split::top(
|
||||
theme::BUTTON_HEIGHT,
|
||||
theme::BUTTON_SPACING,
|
||||
btn(0, top),
|
||||
Split::horizontal(
|
||||
Split::top(
|
||||
theme::BUTTON_HEIGHT,
|
||||
theme::BUTTON_SPACING,
|
||||
btn(1, middle),
|
||||
|
131
core/embed/rust/src/ui/model_tt/component/coinjoin_progress.rs
Normal file
131
core/embed/rust/src/ui/model_tt/component/coinjoin_progress.rs
Normal file
@ -0,0 +1,131 @@
|
||||
use core::mem;
|
||||
|
||||
use crate::ui::{
|
||||
component::{
|
||||
base::Never, painter, Child, Component, ComponentExt, Empty, Event, EventCtx, Label, Split,
|
||||
},
|
||||
display::loader::{loader_circular_uncompress, LoaderDimensions},
|
||||
geometry::{Alignment, Insets, Rect},
|
||||
util::animation_disabled,
|
||||
};
|
||||
|
||||
use super::{theme, Frame};
|
||||
|
||||
const RECTANGLE_HEIGHT: i16 = 56;
|
||||
const LABEL_TOP: i16 = 135;
|
||||
const LOADER_OUTER: i16 = 39;
|
||||
const LOADER_INNER: i16 = 28;
|
||||
const LOADER_OFFSET: i16 = -34;
|
||||
const LOADER_SPEED: u16 = 5;
|
||||
|
||||
pub struct CoinJoinProgress<T, U> {
|
||||
value: u16,
|
||||
indeterminate: bool,
|
||||
content: Child<Frame<Split<Empty, U>, &'static str>>,
|
||||
// Label is not a child since circular loader paints large black rectangle which overlaps it.
|
||||
// To work around this, draw label every time loader is drawn.
|
||||
label: Label<T>,
|
||||
}
|
||||
|
||||
impl<T, U> CoinJoinProgress<T, U>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
pub fn new(text: T, indeterminate: bool) -> CoinJoinProgress<T, impl Component<Msg = Never>>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
let style = theme::label_coinjoin_progress();
|
||||
let label = Label::centered("DO NOT DISCONNECT YOUR TREZOR!", style)
|
||||
.vertically_aligned(Alignment::Center);
|
||||
let bg = painter::rect_painter(style.background_color, theme::BG);
|
||||
let inner = (bg, label);
|
||||
CoinJoinProgress::with_background(text, inner, indeterminate)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> CoinJoinProgress<T, U>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
U: Component<Msg = Never>,
|
||||
{
|
||||
pub fn with_background(text: T, inner: U, indeterminate: bool) -> Self {
|
||||
Self {
|
||||
value: 0,
|
||||
indeterminate,
|
||||
content: Frame::left_aligned(
|
||||
theme::label_title(),
|
||||
"COINJOIN IN PROGRESS",
|
||||
Split::bottom(RECTANGLE_HEIGHT, 0, Empty, inner),
|
||||
)
|
||||
.into_child(),
|
||||
label: Label::centered(text, theme::TEXT_NORMAL),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Component for CoinJoinProgress<T, U>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
U: Component<Msg = Never>,
|
||||
{
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.content.place(bounds);
|
||||
let label_bounds = bounds.inset(Insets::top(LABEL_TOP));
|
||||
self.label.place(label_bounds);
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
self.content.event(ctx, event);
|
||||
self.label.event(ctx, event);
|
||||
match event {
|
||||
_ if animation_disabled() => {
|
||||
return None;
|
||||
}
|
||||
Event::Attach if self.indeterminate => {
|
||||
ctx.request_anim_frame();
|
||||
}
|
||||
Event::Timer(EventCtx::ANIM_FRAME_TIMER) => {
|
||||
self.value = (self.value + LOADER_SPEED) % 1000;
|
||||
ctx.request_anim_frame();
|
||||
ctx.request_paint();
|
||||
}
|
||||
Event::Progress(new_value, _new_description) => {
|
||||
if mem::replace(&mut self.value, new_value) != new_value {
|
||||
ctx.request_paint();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.content.paint();
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
LOADER_OFFSET,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
self.value,
|
||||
self.indeterminate,
|
||||
None,
|
||||
);
|
||||
self.label.paint();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<T, U> crate::trace::Trace for CoinJoinProgress<T, U>
|
||||
where
|
||||
T: crate::trace::Trace,
|
||||
U: Component,
|
||||
{
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("CoinJoinProgress");
|
||||
t.close();
|
||||
}
|
||||
}
|
@ -62,6 +62,7 @@ where
|
||||
|
||||
fn level_to_style(level: u8) -> (Color, Icon) {
|
||||
match level {
|
||||
3 => (theme::YELLOW, Icon::new(theme::ICON_COINJOIN)),
|
||||
2 => (theme::VIOLET, Icon::new(theme::ICON_MAGIC)),
|
||||
1 => (theme::YELLOW, Icon::new(theme::ICON_WARN)),
|
||||
_ => (theme::RED, Icon::new(theme::ICON_WARN)),
|
||||
|
@ -1,5 +1,6 @@
|
||||
mod address_details;
|
||||
mod button;
|
||||
mod coinjoin_progress;
|
||||
mod dialog;
|
||||
mod fido;
|
||||
#[rustfmt::skip]
|
||||
@ -24,6 +25,7 @@ pub use button::{
|
||||
Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg,
|
||||
CancelInfoConfirmMsg, IconText, SelectWordMsg,
|
||||
};
|
||||
pub use coinjoin_progress::CoinJoinProgress;
|
||||
pub use dialog::{Dialog, DialogMsg, IconDialog};
|
||||
pub use fido::{FidoConfirm, FidoMsg};
|
||||
pub use frame::{Frame, FrameMsg, NotificationFrame};
|
||||
|
@ -5,8 +5,8 @@ pub const HEIGHT: i16 = 240;
|
||||
pub const LINE_SPACE: i16 = 4;
|
||||
pub const FONT_BPP: i16 = 4;
|
||||
|
||||
pub const LOADER_OUTER: f32 = 60_f32;
|
||||
pub const LOADER_INNER: f32 = 42_f32;
|
||||
pub const LOADER_OUTER: i16 = 60;
|
||||
pub const LOADER_INNER: i16 = 42;
|
||||
pub const LOADER_ICON_MAX_SIZE: i16 = 64;
|
||||
|
||||
pub const BACKLIGHT_NORMAL: i32 = 150;
|
||||
|
@ -28,7 +28,7 @@ use crate::{
|
||||
},
|
||||
TextStyle,
|
||||
},
|
||||
Border, Component, Empty, FormattedText, Qr, Timeout, TimeoutMsg,
|
||||
Border, Component, Empty, FormattedText, Never, Qr, Timeout, TimeoutMsg,
|
||||
},
|
||||
display::{self, tjpgd::jpeg_info, toif::Icon},
|
||||
geometry,
|
||||
@ -46,12 +46,12 @@ use crate::{
|
||||
use super::{
|
||||
component::{
|
||||
AddressDetails, Bip39Input, Button, ButtonMsg, ButtonStyleSheet, CancelConfirmMsg,
|
||||
CancelInfoConfirmMsg, Dialog, DialogMsg, FidoConfirm, FidoMsg, Frame, FrameMsg,
|
||||
HoldToConfirm, HoldToConfirmMsg, Homescreen, HomescreenMsg, HorizontalPage, IconDialog,
|
||||
Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, NotificationFrame,
|
||||
NumberInputDialog, NumberInputDialogMsg, PassphraseKeyboard, PassphraseKeyboardMsg,
|
||||
PinKeyboard, PinKeyboardMsg, Progress, SelectWordCount, SelectWordCountMsg, SelectWordMsg,
|
||||
Slip39Input, SwipeHoldPage, SwipePage, WelcomeScreen,
|
||||
CancelInfoConfirmMsg, CoinJoinProgress, Dialog, DialogMsg, FidoConfirm, FidoMsg, Frame,
|
||||
FrameMsg, HoldToConfirm, HoldToConfirmMsg, Homescreen, HomescreenMsg, HorizontalPage,
|
||||
IconDialog, Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg,
|
||||
NotificationFrame, NumberInputDialog, NumberInputDialogMsg, PassphraseKeyboard,
|
||||
PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress, SelectWordCount,
|
||||
SelectWordCountMsg, SelectWordMsg, Slip39Input, SwipeHoldPage, SwipePage, WelcomeScreen,
|
||||
},
|
||||
constant, theme,
|
||||
};
|
||||
@ -336,6 +336,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ComponentMsgObj for (Timeout, T)
|
||||
where
|
||||
T: Component<Msg = TimeoutMsg>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
TimeoutMsg::TimedOut => Ok(CANCELLED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentMsgObj for Qr {
|
||||
fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result<Obj, Error> {
|
||||
unreachable!();
|
||||
@ -365,6 +376,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ComponentMsgObj for CoinJoinProgress<T, U>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
U: Component<Msg = Never>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result<Obj, Error> {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
@ -1064,9 +1085,9 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut
|
||||
let max_feerate: StrBuffer = kwargs.get(Qstr::MP_QSTR_max_feerate)?.try_into()?;
|
||||
|
||||
let paragraphs = Paragraphs::new([
|
||||
Paragraph::new(&theme::TEXT_NORMAL, "Maximum rounds:".into()),
|
||||
Paragraph::new(&theme::TEXT_NORMAL, "Max rounds".into()),
|
||||
Paragraph::new(&theme::TEXT_MONO, max_rounds),
|
||||
Paragraph::new(&theme::TEXT_NORMAL, "Maximum mining fee:".into()),
|
||||
Paragraph::new(&theme::TEXT_NORMAL, "Max mining fee".into()),
|
||||
Paragraph::new(&theme::TEXT_MONO, max_feerate),
|
||||
]);
|
||||
|
||||
@ -1390,6 +1411,30 @@ extern "C" fn new_show_progress(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_show_progress_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let indeterminate: bool = kwargs.get_or(Qstr::MP_QSTR_indeterminate, false)?;
|
||||
let time_ms: u32 = kwargs.get_or(Qstr::MP_QSTR_time_ms, 0)?;
|
||||
let skip_first_paint: bool = kwargs.get_or(Qstr::MP_QSTR_skip_first_paint, false)?;
|
||||
|
||||
// The second type parameter is actually not used in `new()` but we need to
|
||||
// provide it.
|
||||
let progress = CoinJoinProgress::<_, Never>::new(title, indeterminate);
|
||||
let obj = if time_ms > 0 && indeterminate {
|
||||
let timeout = Timeout::new(time_ms);
|
||||
LayoutObj::new((timeout, progress.map(|_msg| None)))?
|
||||
} else {
|
||||
LayoutObj::new(progress)?
|
||||
};
|
||||
if skip_first_paint {
|
||||
obj.skip_first_paint();
|
||||
}
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_show_homescreen(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let label: StrBuffer = kwargs.get(Qstr::MP_QSTR_label)?.try_into()?;
|
||||
@ -1424,31 +1469,6 @@ extern "C" fn new_show_lockscreen(n_args: usize, args: *const Obj, kwargs: *mut
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_show_busyscreen(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.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 skip_first_paint: bool = kwargs.get(Qstr::MP_QSTR_skip_first_paint)?.try_into()?;
|
||||
|
||||
let obj = LayoutObj::new(Frame::left_aligned(
|
||||
theme::label_title(),
|
||||
title,
|
||||
Dialog::new(
|
||||
Paragraphs::new(Paragraph::new(&theme::TEXT_NORMAL, description).centered()),
|
||||
Timeout::new(time_ms).map(|msg| {
|
||||
(matches!(msg, TimeoutMsg::TimedOut)).then(|| CancelConfirmMsg::Cancelled)
|
||||
}),
|
||||
),
|
||||
))?;
|
||||
if skip_first_paint {
|
||||
obj.skip_first_paint();
|
||||
}
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn draw_welcome_screen() -> Obj {
|
||||
// No need of util::try_or_raise, this does not allocate
|
||||
let mut screen = WelcomeScreen::new();
|
||||
@ -1822,6 +1842,17 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// make sure the initial desciption has at least that amount of lines."""
|
||||
Qstr::MP_QSTR_show_progress => obj_fn_kw!(0, new_show_progress).as_obj(),
|
||||
|
||||
/// def show_progress_coinjoin(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// indeterminate: bool = False,
|
||||
/// time_ms: int = 0,
|
||||
/// skip_first_paint: bool = False,
|
||||
/// ) -> object:
|
||||
/// """Show progress loader for coinjoin. Returns CANCELLED after a specified time when
|
||||
/// time_ms timeout is passed."""
|
||||
Qstr::MP_QSTR_show_progress_coinjoin => obj_fn_kw!(0, new_show_progress_coinjoin).as_obj(),
|
||||
|
||||
/// def show_homescreen(
|
||||
/// *,
|
||||
/// label: str,
|
||||
@ -1842,16 +1873,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Homescreen for locked device."""
|
||||
Qstr::MP_QSTR_show_lockscreen => obj_fn_kw!(0, new_show_lockscreen).as_obj(),
|
||||
|
||||
/// def show_busyscreen(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// description: str,
|
||||
/// time_ms: int,
|
||||
/// skip_first_paint: bool,
|
||||
/// ) -> CANCELLED:
|
||||
/// """Homescreen used for indicating coinjoin in progress."""
|
||||
Qstr::MP_QSTR_show_busyscreen => obj_fn_kw!(0, new_show_busyscreen).as_obj(),
|
||||
|
||||
/// def draw_welcome_screen() -> None:
|
||||
/// """Show logo icon with the model name at the bottom and return."""
|
||||
Qstr::MP_QSTR_draw_welcome_screen => obj_fn_0!(draw_welcome_screen).as_obj(),
|
||||
|
@ -152,6 +152,10 @@ pub const fn label_title() -> TextStyle {
|
||||
TextStyle::new(Font::BOLD, GREY_LIGHT, BG, GREY_LIGHT, GREY_LIGHT)
|
||||
}
|
||||
|
||||
pub const fn label_coinjoin_progress() -> TextStyle {
|
||||
TextStyle::new(Font::BOLD, FG, YELLOW, FG, FG)
|
||||
}
|
||||
|
||||
pub const fn button_default() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
|
@ -422,6 +422,18 @@ def show_progress(
|
||||
make sure the initial desciption has at least that amount of lines."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def show_progress_coinjoin(
|
||||
*,
|
||||
title: str,
|
||||
indeterminate: bool = False,
|
||||
time_ms: int = 0,
|
||||
skip_first_paint: bool = False,
|
||||
) -> object:
|
||||
"""Show progress loader for coinjoin. Returns CANCELLED after a specified time when
|
||||
time_ms timeout is passed."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def show_homescreen(
|
||||
*,
|
||||
@ -444,17 +456,6 @@ def show_lockscreen(
|
||||
"""Homescreen for locked device."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def show_busyscreen(
|
||||
*,
|
||||
title: str,
|
||||
description: str,
|
||||
time_ms: int,
|
||||
skip_first_paint: bool,
|
||||
) -> CANCELLED:
|
||||
"""Homescreen used for indicating coinjoin in progress."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def draw_welcome_screen() -> None:
|
||||
"""Show logo icon with the model name at the bottom and return."""
|
||||
|
@ -263,8 +263,8 @@ async def handle_UnlockPath(ctx: wire.Context, msg: UnlockPath) -> protobuf.Mess
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"confirm_coinjoin_access",
|
||||
title="Coinjoin account",
|
||||
description="Do you want to allow access to your coinjoin account?",
|
||||
title="Coinjoin",
|
||||
description="Do you want to access your coinjoin account?",
|
||||
)
|
||||
|
||||
wire_types = (MessageType.GetAddress, MessageType.GetPublicKey, MessageType.SignTx)
|
||||
|
@ -13,6 +13,7 @@ from ..common import SigHashType, ecdsa_sign, input_is_external
|
||||
from ..ownership import verify_nonownership
|
||||
from ..verification import SignatureVerifier
|
||||
from . import helpers
|
||||
from .approvers import CoinJoinApprover
|
||||
from .helpers import request_tx_input, request_tx_output
|
||||
from .progress import progress
|
||||
from .tx_info import OriginalTxInfo
|
||||
@ -47,7 +48,9 @@ _SERIALIZED_TX_BUFFER = empty_bytearray(_MAX_SERIALIZED_CHUNK_SIZE)
|
||||
|
||||
class Bitcoin:
|
||||
async def signer(self) -> None:
|
||||
progress.init(self.tx_info.tx)
|
||||
progress.init(
|
||||
self.tx_info.tx, is_coinjoin=isinstance(self.approver, CoinJoinApprover)
|
||||
)
|
||||
|
||||
# Add inputs to sig_hasher and h_tx_check and compute the sum of input amounts.
|
||||
await self.step1_process_inputs()
|
||||
|
@ -16,6 +16,7 @@ class Progress:
|
||||
self.progress = 0
|
||||
self.steps = 0
|
||||
self.signing = False
|
||||
self.is_coinjoin = False
|
||||
|
||||
# We don't know how long it will take to fetch the previous transactions,
|
||||
# so for each one we reserve _PREV_TX_MULTIPLIER steps in the signing
|
||||
@ -24,9 +25,10 @@ class Progress:
|
||||
# prev_tx input or output in the overall signing progress.
|
||||
self.prev_tx_step = 0
|
||||
|
||||
def init(self, tx: SignTx) -> None:
|
||||
def init(self, tx: SignTx, is_coinjoin: bool = False) -> None:
|
||||
self.progress = 0
|
||||
self.signing = False
|
||||
self.is_coinjoin = is_coinjoin
|
||||
|
||||
# Step 1 and 2 - load inputs and outputs
|
||||
self.steps = tx.inputs_count + tx.outputs_count
|
||||
@ -109,13 +111,16 @@ class Progress:
|
||||
|
||||
def report_init(self) -> None:
|
||||
from trezor import workflow
|
||||
from trezor.ui.layouts import bitcoin_progress
|
||||
from trezor.ui.layouts import bitcoin_progress, coinjoin_progress
|
||||
|
||||
progress_layout = bitcoin_progress
|
||||
if self.is_coinjoin:
|
||||
progress_layout = coinjoin_progress
|
||||
workflow.close_others()
|
||||
if self.signing:
|
||||
self.progress_layout = bitcoin_progress("Signing transaction")
|
||||
self.progress_layout = progress_layout("Signing transaction")
|
||||
else:
|
||||
self.progress_layout = bitcoin_progress("Loading transaction")
|
||||
self.progress_layout = progress_layout("Loading transaction")
|
||||
|
||||
def report(self) -> None:
|
||||
from trezor import utils
|
||||
|
@ -2,9 +2,11 @@ import storage
|
||||
import storage.cache
|
||||
import storage.device
|
||||
from trezor import config, wire
|
||||
from trezor.enums import MessageType
|
||||
from trezor.ui.layouts.homescreen import Busyscreen, Homescreen, Lockscreen
|
||||
|
||||
from apps.base import busy_expiry_ms, lock_device
|
||||
from apps.common.authorization import is_set_any_session
|
||||
|
||||
|
||||
async def busyscreen() -> None:
|
||||
@ -19,18 +21,20 @@ async def homescreen() -> None:
|
||||
|
||||
notification = None
|
||||
notification_is_error = False
|
||||
if storage.device.is_initialized() and storage.device.no_backup():
|
||||
if is_set_any_session(MessageType.AuthorizeCoinJoin):
|
||||
notification = "COINJOIN AUTHORIZED"
|
||||
elif storage.device.is_initialized() and storage.device.no_backup():
|
||||
notification = "SEEDLESS"
|
||||
notification_is_error = True
|
||||
elif storage.device.is_initialized() and storage.device.unfinished_backup():
|
||||
notification = "BACKUP FAILED!"
|
||||
notification = "BACKUP FAILED"
|
||||
notification_is_error = True
|
||||
elif storage.device.is_initialized() and storage.device.needs_backup():
|
||||
notification = "NEEDS BACKUP!"
|
||||
notification = "NEEDS BACKUP"
|
||||
elif storage.device.is_initialized() and not config.has_pin():
|
||||
notification = "PIN NOT SET!"
|
||||
notification = "PIN NOT SET"
|
||||
elif storage.device.get_experimental_features():
|
||||
notification = "EXPERIMENTAL MODE!"
|
||||
notification = "EXPERIMENTAL MODE"
|
||||
|
||||
await Homescreen(
|
||||
label=label,
|
||||
|
@ -1135,15 +1135,9 @@ async def request_pin_on_device(
|
||||
class RustProgress:
|
||||
def __init__(
|
||||
self,
|
||||
title: str,
|
||||
description: str | None = None,
|
||||
indeterminate: bool = False,
|
||||
layout: Any,
|
||||
):
|
||||
self.layout: Any = trezorui2.show_progress(
|
||||
title=title.upper(),
|
||||
indeterminate=indeterminate,
|
||||
description=description or "",
|
||||
)
|
||||
self.layout = layout
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||
ui.display.clear()
|
||||
self.layout.attach_timer_fn(self.set_timer)
|
||||
@ -1160,25 +1154,41 @@ class RustProgress:
|
||||
ui.refresh()
|
||||
|
||||
|
||||
def progress(message: str = "PLEASE WAIT") -> ProgressLayout:
|
||||
return RustProgress(message.upper())
|
||||
def progress(
|
||||
message: str = "PLEASE WAIT",
|
||||
description: str | None = None,
|
||||
indeterminate: bool = False,
|
||||
) -> ProgressLayout:
|
||||
return RustProgress(
|
||||
layout=trezorui2.show_progress(
|
||||
title=message.upper(),
|
||||
indeterminate=indeterminate,
|
||||
description=description or "",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def bitcoin_progress(message: str) -> ProgressLayout:
|
||||
return RustProgress(message.upper())
|
||||
return progress(message)
|
||||
|
||||
|
||||
def coinjoin_progress(message: str) -> ProgressLayout:
|
||||
return RustProgress(
|
||||
layout=trezorui2.show_progress_coinjoin(title=message, indeterminate=False)
|
||||
)
|
||||
|
||||
|
||||
def pin_progress(message: str, description: str) -> ProgressLayout:
|
||||
return RustProgress(message.upper(), description=description)
|
||||
return progress(message, description=description)
|
||||
|
||||
|
||||
def monero_keyimage_sync_progress() -> ProgressLayout:
|
||||
return RustProgress("SYNCING")
|
||||
return progress("SYNCING")
|
||||
|
||||
|
||||
def monero_live_refresh_progress() -> ProgressLayout:
|
||||
return RustProgress("REFRESHING", description="", indeterminate=True)
|
||||
return progress("REFRESHING", indeterminate=True)
|
||||
|
||||
|
||||
def monero_transaction_progress_inner() -> ProgressLayout:
|
||||
return RustProgress("SIGNING TRANSACTION", description="")
|
||||
return progress("SIGNING TRANSACTION")
|
||||
|
@ -47,7 +47,9 @@ class Homescreen(HomescreenBase):
|
||||
level = 1
|
||||
if notification is not None:
|
||||
notification = notification.rstrip("!")
|
||||
if "EXPERIMENTAL" in notification:
|
||||
if "COINJOIN" in notification.upper():
|
||||
level = 3
|
||||
elif "EXPERIMENTAL" in notification.upper():
|
||||
level = 2
|
||||
elif notification_is_error:
|
||||
level = 0
|
||||
@ -114,9 +116,9 @@ class Busyscreen(HomescreenBase):
|
||||
def __init__(self, delay_ms: int) -> None:
|
||||
skip = storage_cache.homescreen_shown is self.RENDER_INDICATOR
|
||||
super().__init__(
|
||||
layout=trezorui2.show_busyscreen(
|
||||
title="PLEASE WAIT",
|
||||
description="Coinjoin in progress.\n\nDo not disconnect your\nTrezor.",
|
||||
layout=trezorui2.show_progress_coinjoin(
|
||||
title="Waiting for others",
|
||||
indeterminate=True,
|
||||
time_ms=delay_ms,
|
||||
skip_first_paint=skip,
|
||||
)
|
||||
|
@ -715,16 +715,16 @@
|
||||
"TT_binance-test_sign_tx.py::test_binance_sign_message[message0-expected_response0]": "6367706336b7063b5f8850034afb948c8e9cda571d3b40f0d69f73d743eb72e2",
|
||||
"TT_binance-test_sign_tx.py::test_binance_sign_message[message1-expected_response1]": "78b3b0efe134085ed595dcc859f53e39b2f044c3ae17e52ef7ff74d33303f5a9",
|
||||
"TT_binance-test_sign_tx.py::test_binance_sign_message[message2-expected_response2]": "9f6d84a0081925d4d7ffc43765394e2e3c065a34c3fc00b4c9d8f6dbb108796e",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_cancel_authorization": "9903e6dc03e36e73bd36d96e8e4eb28706ae8a47015605b328c977bb39e9b202",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_get_address": "5556ff2531268efa0eda447a1960324c78ff43d79c1f7d91d2d6ddd772275799",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_get_public_key": "f79cc8fce59d48aa49bc791cbb00d63676dbbd616eb94b4aa0ca56a1c89cf3a0",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_multisession_authorization": "8e0a38d46f5a28ed8c7b4608ba5f02b9c3b82a70b01c9bd7319392b0eea272dd",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx": "21954223b2382156eb2926136239cd983ab94fc0d7060ad87e14d35a098276ea",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_large": "eb9e47aaee7b932845a0f94a9f52b3107ce1eb19ba12f63f3d7b464335508634",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "d619b7d8ff6124885969c543603c49952ea07917a58fb5d80592b4f5bb5c8495",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "69649e183ca47887d8363d63996a4ddac2dfc9ebd23e53c9855bb8d30bcc868a",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_wrong_account_type": "9903e6dc03e36e73bd36d96e8e4eb28706ae8a47015605b328c977bb39e9b202",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_wrong_coordinator": "9903e6dc03e36e73bd36d96e8e4eb28706ae8a47015605b328c977bb39e9b202",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_cancel_authorization": "a06b2f2471bb928f36dc43e6f7ad03d8b19dadb77ed6e968830cbdf84e0ee2bc",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_get_address": "a02623c612e54300d8f9f9d0760282f8ea9be9663b30257797eade328fa30a75",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_get_public_key": "064eb02d220e974352247d3b7065c38dd3d4fa3d0c5571574bf0d80f369b69d1",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_multisession_authorization": "b28769468af2ddf2e4b2e45b0bc89806a6392b082cc8953013795eb32b692890",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx": "a7a3307a96425a843617d341cf559d0898813ba1eec8221e911a153141aaade8",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_large": "a45463660d3c6f920c7d31f6c054a39e504cb152e9eacd0f817aa081a3c7502b",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "b92179f9e59ea76c6410cdfb3402efc33f05a1e75abfee842cb63380cfa4ad94",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "2a086b16a7339f09db438f9a6416a48d2b4e99945a8f1365800d4373158d09a8",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_wrong_account_type": "a06b2f2471bb928f36dc43e6f7ad03d8b19dadb77ed6e968830cbdf84e0ee2bc",
|
||||
"TT_bitcoin-test_authorize_coinjoin.py::test_wrong_coordinator": "a06b2f2471bb928f36dc43e6f7ad03d8b19dadb77ed6e968830cbdf84e0ee2bc",
|
||||
"TT_bitcoin-test_bcash.py::test_attack_change_input": "01c388c7836bf584f7d463412ed8dfc18267173759779572b59f8a92831d587d",
|
||||
"TT_bitcoin-test_bcash.py::test_send_bch_change": "b33fb94f9b7a27db131a025a58e7d1e9130455b56e2a9664a6601126798c5faa",
|
||||
"TT_bitcoin-test_bcash.py::test_send_bch_external_presigned": "be3c96271c3fa8084f94f3108a283059b625240c8479ae8509e4e61e2e7801b1",
|
||||
@ -748,7 +748,7 @@
|
||||
"TT_bitcoin-test_decred.py::test_send_decred": "7aea7d3be283f95c73494d1298cf45f0914e4bd2b563b6ee06822e5475c7cdee",
|
||||
"TT_bitcoin-test_decred.py::test_send_decred_change": "f1ba6140197b01fcdc6f5e7657dfec8608e19cfd161ddf94273cd057afee7fe5",
|
||||
"TT_bitcoin-test_decred.py::test_spend_from_stake_generation_and_revocation_decred": "925e48742feacc62b02e4fcab707a3f7fe6ea8779e77e49e94a452416c844579",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-10025-InputScriptType.SPENDTAPROOT--ad9e3c78": "29bd3ff77013039b56947adecc7ca4971d9cdc3c6c084232a2e6cb7b61cdf322",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-10025-InputScriptType.SPENDTAPROOT--ad9e3c78": "9ef6e1b1d30c95b00c52957eda428f0135b67b3ac51febb571b0b37c7959a201",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-44-InputScriptType.SPENDADDRESS-pkh-efa37663": "5a7da5c231515010c7c9355f571c2ea44743e06f4e603b11475790ac47620369",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-49-InputScriptType.SPENDP2SHWITNESS-77f1e2d2": "16d7bd9d6a2d7f3fbd3cd4f57b4d41bd22181d1815f3f3e8ceab8c71c7a1e217",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-84-InputScriptType.SPENDWITNESS-wpk-16507754": "33742a9a1db97e160bae2399272f9ed2d1e4457efb9f1cdda5724bda09d285e8",
|
||||
@ -757,7 +757,7 @@
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-49-InputScriptType.SPENDP2SHWITNESS-965f4fa3": "70e6bbb4990ce9185fad968524081d31f2fdd6d4663223fb798cf0f186dfef70",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-84-InputScriptType.SPENDWITNESS-wpk-c761bcc8": "b07033a54a4115479d1fb1227ea6895d9661d4f304ca39c0636c2f32504e6eb0",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-86-InputScriptType.SPENDTAPROOT-tr(-686799ea": "c55d9c0796573c26c4ab2ab42805fcffc51c74349ee15da19d45f849443a7c09",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-10025-InputScriptType.SPENDTAPROOT--77d3a71b": "37b2f77f05f6b55ae4af5da2343e1ddad44afe52e84b6d63d00effd233a464ee",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-10025-InputScriptType.SPENDTAPROOT--77d3a71b": "b136a9f101bd3c1f462dba38211ce88555b57f217216918388b5dda397b71f9d",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-44-InputScriptType.SPENDADDRESS-pkh-a26143a7": "c1510c3bfff3a635ba9f01d3d292b795b135fd32f89edfbd211609bfb3b9fb18",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-49-InputScriptType.SPENDP2SHWITNESS-195ebda5": "6a44ff76861f8b45fcf02d8231eba4c7d7be2e36acbc83245daab8bf1e139e69",
|
||||
"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-84-InputScriptType.SPENDWITNESS-wpk-68f8b526": "4668aded2297e0aaa149c1e3c81016add52c6a273df6709360f3e3f239b59be0",
|
||||
@ -1729,8 +1729,8 @@
|
||||
"TT_test_basic.py::test_device_id_same": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3",
|
||||
"TT_test_basic.py::test_features": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3",
|
||||
"TT_test_basic.py::test_ping": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3",
|
||||
"TT_test_busy_state.py::test_busy_expiry": "b67d51c7c3e2ebf4318f249c48badc0fceb907fedeb99de4fc6b6d196389bf69",
|
||||
"TT_test_busy_state.py::test_busy_state": "b549edd509bde87496aea924d9b9df251893d3a901afc46a5a61605abe7022fb",
|
||||
"TT_test_busy_state.py::test_busy_expiry": "ba86a3b442bcc2709762a008734511cf5d7ddd715f7184e9006061b8046e2d56",
|
||||
"TT_test_busy_state.py::test_busy_state": "201b1a28a61556a030f1991e5f88925f1bc3db9ef421e4bc99a323505212f7ef",
|
||||
"TT_test_cancel.py::test_cancel_message_via_cancel[message0]": "1bd3157d54327e33542f89dcac6c7cd23808f7c9aa1b0adb390e5fcc1fd858a5",
|
||||
"TT_test_cancel.py::test_cancel_message_via_cancel[message1]": "1bd3157d54327e33542f89dcac6c7cd23808f7c9aa1b0adb390e5fcc1fd858a5",
|
||||
"TT_test_cancel.py::test_cancel_message_via_initialize[message0]": "1bd3157d54327e33542f89dcac6c7cd23808f7c9aa1b0adb390e5fcc1fd858a5",
|
||||
|
Loading…
Reference in New Issue
Block a user