Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/.changelog.d/6348.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Avoid failing backup flow on I/O errors.
4 changes: 2 additions & 2 deletions core/embed/rust/src/ui/api/firmware_micropython.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1274,7 +1274,7 @@ extern "C" fn new_show_wait_text(message: Obj) -> Obj {

extern "C" fn new_show_warning(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let title: Option<TString> = kwargs.get(Qstr::MP_QSTR_title)?.try_into_option()?;
let button: TString = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?;
let value: TString = kwargs.get_or(Qstr::MP_QSTR_value, "".into())?;
let description: TString = kwargs.get_or(Qstr::MP_QSTR_description, "".into())?;
Expand Down Expand Up @@ -2155,7 +2155,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {

/// def show_warning(
/// *,
/// title: str,
/// title: str | None,
/// button: str,
/// value: str = "",
/// description: str = "",
Expand Down
45 changes: 30 additions & 15 deletions core/embed/rust/src/ui/layout_bolt/component/dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ where
}

pub struct IconDialog<U> {
image: Child<BlendedImage>,
image: Option<Child<BlendedImage>>,
paragraphs: Paragraphs<ParagraphVecShort<'static>>,
controls: Child<U>,
}
Expand All @@ -97,15 +97,21 @@ impl<U> IconDialog<U>
where
U: Component,
{
pub fn new(icon: BlendedImage, title: impl Into<TString<'static>>, controls: U) -> Self {
pub fn new(
icon: BlendedImage,
title: Option<impl Into<TString<'static>>>,
controls: U,
) -> Self {
let (image, paragraphs) = if let Some(title) = title {
let title = Paragraph::new(&theme::TEXT_DEMIBOLD, title).centered();
let para = ParagraphVecShort::from_iter([title]);
(Some(Child::new(icon)), para)
} else {
(None, ParagraphVecShort::new())
};
Self {
image: Child::new(icon),
paragraphs: Paragraphs::new(ParagraphVecShort::from_iter([Paragraph::new(
&theme::TEXT_DEMIBOLD,
title,
)
.centered()]))
.with_placement(
image,
paragraphs: Paragraphs::new(paragraphs).with_placement(
LinearPlacement::vertical()
.align_at_center()
.with_spacing(Self::VALUE_SPACE),
Expand Down Expand Up @@ -138,13 +144,13 @@ where
pub fn new_shares(lines: [impl Into<TString<'static>>; 4], controls: U) -> Self {
let [l0, l1, l2, l3] = lines;
Self {
image: Child::new(BlendedImage::new(
image: Some(Child::new(BlendedImage::new(
theme::IMAGE_BG_CIRCLE,
theme::IMAGE_FG_SUCCESS,
theme::SUCCESS_COLOR,
theme::FG,
theme::BG,
)),
))),
paragraphs: ParagraphVecShort::from_iter([
Paragraph::new(&theme::TEXT_NORMAL_OFF_WHITE, l0).centered(),
Paragraph::new(&theme::TEXT_DEMIBOLD, l1).centered(),
Expand Down Expand Up @@ -176,9 +182,14 @@ where
let controls_area = self.controls.place(bounds);
let content_area = bounds.inset(Insets::bottom(controls_area.height()));

let (image_area, content_area) = content_area.split_top(Self::ICON_AREA_HEIGHT);
let content_area = if let Some(image) = &mut self.image {
let (image_area, content_area) = content_area.split_top(Self::ICON_AREA_HEIGHT);
image.place(image_area);
content_area
} else {
content_area
};

self.image.place(image_area);
self.paragraphs.place(content_area);
bounds
}
Expand All @@ -189,7 +200,9 @@ where
}

fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
self.image.render(target);
if let Some(image) = &self.image {
image.render(target);
}
self.paragraphs.render(target);
self.controls.render(target);
}
Expand All @@ -202,7 +215,9 @@ where
{
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("IconDialog");
t.child("image", &self.image);
if let Some(image) = &self.image {
t.child("image", image);
}
t.child("content", &self.paragraphs);
t.child("controls", &self.controls);
}
Expand Down
18 changes: 11 additions & 7 deletions core/embed/rust/src/ui/layout_bolt/ui_firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,7 @@ impl FirmwareUI for UIBolt {
theme::BG,
);
new_show_modal(
title,
Some(title),
TString::empty(),
description,
(!button.is_empty()).then_some(button),
Expand Down Expand Up @@ -1015,7 +1015,7 @@ impl FirmwareUI for UIBolt {
theme::BG,
);
new_show_modal(
title,
Some(title),
TString::empty(),
description,
button_text,
Expand Down Expand Up @@ -1089,7 +1089,7 @@ impl FirmwareUI for UIBolt {
let layout = RootComponent::new(
IconDialog::new(
icon,
title,
Some(title),
Button::cancel_confirm(
Button::with_icon(theme::ICON_BACK),
Button::with_text(button).styled(theme::button_reset()),
Expand Down Expand Up @@ -1253,7 +1253,7 @@ impl FirmwareUI for UIBolt {
theme::BG,
);
new_show_modal(
title,
Some(title),
TString::empty(),
description,
(!button.is_empty()).then_some(button),
Expand All @@ -1271,12 +1271,12 @@ impl FirmwareUI for UIBolt {
}

fn show_warning(
title: TString<'static>,
title: Option<TString<'static>>,
button: TString<'static>,
value: TString<'static>,
description: TString<'static>,
allow_cancel: bool,
_danger: bool,
danger: bool,
) -> Result<Gc<LayoutObj>, Error> {
let icon = BlendedImage::new(
theme::IMAGE_BG_OCTAGON,
Expand All @@ -1285,6 +1285,10 @@ impl FirmwareUI for UIBolt {
theme::FG,
theme::BG,
);
if danger && title.is_none() {
// Disallow showing "dangerous" warning with no header.
return Err(Error::ValueError(c"Non-empty title is required"));
}
new_show_modal(
title,
value,
Expand All @@ -1308,7 +1312,7 @@ impl FirmwareUI for UIBolt {

#[allow(clippy::too_many_arguments)]
fn new_show_modal(
title: TString<'static>,
title: Option<TString<'static>>,
value: TString<'static>,
description: TString<'static>,
button: Option<TString<'static>>,
Expand Down
2 changes: 1 addition & 1 deletion core/embed/rust/src/ui/layout_caesar/ui_firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1366,7 +1366,7 @@ impl FirmwareUI for UICaesar {
}

fn show_warning(
_title: TString<'static>,
_title: Option<TString<'static>>,
button: TString<'static>,
value: TString<'static>,
description: TString<'static>,
Expand Down
33 changes: 18 additions & 15 deletions core/embed/rust/src/ui/layout_delizia/ui_firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ impl FirmwareUI for UIDelizia {
}

fn show_warning(
title: TString<'static>,
title: Option<TString<'static>>,
button: TString<'static>,
value: TString<'static>,
description: TString<'static>,
Expand All @@ -1253,22 +1253,25 @@ impl FirmwareUI for UIDelizia {
.into_paragraphs(),
);

let frame = if title.is_empty() {
if danger {
// Disallow showing "dangerous" warning with no header.
return Err(Error::ValueError(c"Non-empty title is required"));
let frame = match title {
None => {
if danger {
// Disallow showing "dangerous" warning with no header.
return Err(Error::ValueError(c"Non-empty title is required"));
}
Frame::content(content)
}
Some(title) => {
let header = Header::left_aligned(title);
let header = if danger {
header.with_danger_icon()
} else {
header.with_warning_low_icon()
};
Frame::with_header(header, content)
}
Frame::content(content)
} else {
let header = Header::left_aligned(title);
let header = if danger {
header.with_danger_icon()
} else {
header.with_warning_low_icon()
};
Frame::with_header(header, content)
};
let frame = if danger {
let frame = if danger || title.is_none() {
frame.with_tap_footer(action)
} else {
frame.with_swipeup_footer(action)
Expand Down
17 changes: 11 additions & 6 deletions core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1546,7 +1546,7 @@ impl FirmwareUI for UIEckhart {
}

fn show_warning(
title: TString<'static>,
title: Option<TString<'static>>,
button: TString<'static>,
value: TString<'static>,
description: TString<'static>,
Expand Down Expand Up @@ -1575,14 +1575,19 @@ impl FirmwareUI for UIEckhart {
ActionBar::new_single(Button::with_text(button))
};
let screen = TextScreen::new(paragraphs).with_action_bar(action_bar);
let screen = if title.is_empty() {
screen
} else {
screen.with_header(
let screen = match title {
None => {
if danger {
// Disallow showing "dangerous" warning with no header.
return Err(Error::ValueError(c"Non-empty title is required"));
}
screen
}
Some(title) => screen.with_header(
Header::new(title)
.with_icon(theme::ICON_INFO, color)
.with_text_style(style),
)
),
};
let layout = LayoutObj::new(screen)?;
Ok(layout)
Expand Down
2 changes: 1 addition & 1 deletion core/embed/rust/src/ui/ui_firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ pub trait FirmwareUI {
fn show_wait_text(text: TString<'static>) -> Result<impl LayoutMaybeTrace, Error>;

fn show_warning(
title: TString<'static>,
title: Option<TString<'static>>,
button: TString<'static>,
value: TString<'static>,
description: TString<'static>,
Expand Down
2 changes: 1 addition & 1 deletion core/mocks/generated/trezorui_api.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ def show_wait_text(message: str, /) -> LayoutObj[None]:
# rust/src/ui/api/firmware_micropython.rs
def show_warning(
*,
title: str,
title: str | None,
button: str,
value: str = "",
description: str = "",
Expand Down
16 changes: 2 additions & 14 deletions core/src/trezor/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@
See `trezor::ui::layout::base::EventCtx::ANIM_FRAME_TIMER`.
"""

_UNRESPONSIVE_WARNING_TIMEOUT_MS = const(2000)


# allow only one alert at a time to avoid alerts overlapping
_alert_in_progress = False

Expand Down Expand Up @@ -84,14 +81,6 @@ def alert(count: int = 3) -> None:
loop.schedule(_alert(count))


async def _waiting_screen() -> None:
from trezor import TR
from trezor.ui.layouts import show_wait_text

await loop.sleep(_UNRESPONSIVE_WARNING_TIMEOUT_MS)
show_wait_text(TR.words__comm_trouble)


class Shutdown(Exception):
pass

Expand Down Expand Up @@ -282,7 +271,7 @@ async def get_result(self) -> T:
if br_handler is not None:
# Make sure ButtonRequest is ACKed, before the result is returned.
# Otherwise, THP channel may become desynced (due to two consecutive writes).
await br_handler.join(_waiting_screen())
await br_handler.join()

return result
finally:
Expand Down Expand Up @@ -342,8 +331,7 @@ def put_button_request(self, msg: ButtonRequestMsg | None) -> bool:
return False

br = ButtonRequest(code=msg[0], name=msg[1], pages=self.layout.page_count())
self.button_request_handler.put(br)
return True
return self.button_request_handler.put(br)

def _paint(self) -> None:
"""Paint the layout and ensure that homescreen cache is properly invalidated."""
Expand Down
Loading
Loading