Skip to content

Commit f5667d4

Browse files
committed
feat(core): allow disabling button on Eckhart show_info() layout
It will be used for N4W1 I/O layouts. [no changelog]
1 parent 5148ab5 commit f5667d4

10 files changed

Lines changed: 95 additions & 71 deletions

File tree

core/embed/rust/src/ui/api/firmware_micropython.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,15 @@ extern "C" fn new_show_info(n_args: usize, args: *const Obj, kwargs: *mut Map) -
10711071
let block = move |_args: &[Obj], kwargs: &Map| {
10721072
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
10731073
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
1074-
let button: TString = kwargs.get_or(Qstr::MP_QSTR_button, TString::empty())?;
1074+
let button = kwargs
1075+
.get(Qstr::MP_QSTR_button)
1076+
.unwrap_or_else(|_| Obj::const_none())
1077+
.try_into_option::<Obj>()?
1078+
.map(|obj| -> Result<(TString<'_>, bool), Error> {
1079+
let [text, enabled]: [Obj; 2] = util::iter_into_array(obj)?;
1080+
Ok((text.try_into()?, enabled.try_into()?))
1081+
})
1082+
.transpose()?;
10751083
let time_ms: u32 = kwargs.get_or(Qstr::MP_QSTR_time_ms, 0)?.try_into()?;
10761084

10771085
let obj = ModelUI::show_info(title, description, button, time_ms)?;
@@ -2012,7 +2020,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
20122020
/// *,
20132021
/// title: str,
20142022
/// description: str = "",
2015-
/// button: str = "",
2023+
/// button: tuple[str, bool] | None = None,
20162024
/// time_ms: int = 0,
20172025
/// ) -> LayoutObj[UiResult]:
20182026
/// """Info screen."""

core/embed/rust/src/ui/layout_bolt/ui_firmware.rs

Lines changed: 71 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ impl FirmwareUI for UIBolt {
884884
title,
885885
TString::empty(),
886886
description,
887-
button,
887+
(!button.is_empty()).then_some(button),
888888
allow_cancel,
889889
time_ms,
890890
icon,
@@ -990,13 +990,17 @@ impl FirmwareUI for UIBolt {
990990
fn show_info(
991991
title: TString<'static>,
992992
description: TString<'static>,
993-
button: TString<'static>,
993+
button: Option<(TString<'static>, bool)>,
994994
time_ms: u32,
995995
) -> Result<Gc<LayoutObj>, Error> {
996-
assert!(
997-
!button.is_empty() || time_ms > 0,
998-
"either button or timeout must be set"
999-
);
996+
let button_text = match (button, time_ms) {
997+
// either button or timeout must be set
998+
(None, 0) => return Err(Error::NotImplementedError),
999+
(None, _) => None,
1000+
// disabled buttons are not supported on Bolt
1001+
(Some((_, false)), _) => return Err(Error::NotImplementedError),
1002+
(Some((text, true)), _) => Some(text),
1003+
};
10001004

10011005
let icon = BlendedImage::new(
10021006
theme::IMAGE_BG_CIRCLE,
@@ -1009,7 +1013,7 @@ impl FirmwareUI for UIBolt {
10091013
title,
10101014
TString::empty(),
10111015
description,
1012-
button,
1016+
button_text,
10131017
false,
10141018
time_ms,
10151019
icon,
@@ -1247,7 +1251,7 @@ impl FirmwareUI for UIBolt {
12471251
title,
12481252
TString::empty(),
12491253
description,
1250-
button,
1254+
(!button.is_empty()).then_some(button),
12511255
allow_cancel,
12521256
time_ms,
12531257
icon,
@@ -1280,7 +1284,7 @@ impl FirmwareUI for UIBolt {
12801284
title,
12811285
value,
12821286
description,
1283-
button,
1287+
(!button.is_empty()).then_some(button),
12841288
allow_cancel,
12851289
0,
12861290
icon,
@@ -1302,62 +1306,70 @@ fn new_show_modal(
13021306
title: TString<'static>,
13031307
value: TString<'static>,
13041308
description: TString<'static>,
1305-
button: TString<'static>,
1309+
button: Option<TString<'static>>,
13061310
allow_cancel: bool,
13071311
time_ms: u32,
13081312
icon: BlendedImage,
13091313
button_style: ButtonStyleSheet,
13101314
) -> Result<Gc<LayoutObj>, Error> {
1311-
let no_buttons = button.is_empty();
1312-
let obj = if no_buttons && time_ms == 0 {
1313-
// No buttons and no timer, used when we only want to draw the dialog once and
1314-
// then throw away the layout object.
1315-
LayoutObj::new(
1316-
IconDialog::new(icon, title, Empty)
1317-
.with_value(value)
1318-
.with_description(description),
1319-
)?
1320-
} else if no_buttons && time_ms > 0 {
1321-
// Timeout, no buttons.
1322-
LayoutObj::new(
1323-
IconDialog::new(
1324-
icon,
1325-
title,
1326-
Timeout::new(time_ms).map(|_| Some(CancelConfirmMsg::Confirmed)),
1327-
)
1328-
.with_value(value)
1329-
.with_description(description),
1330-
)?
1331-
} else if allow_cancel {
1332-
// Two buttons.
1333-
LayoutObj::new(
1334-
IconDialog::new(
1335-
icon,
1336-
title,
1337-
Button::cancel_confirm(
1338-
Button::with_icon(theme::ICON_CANCEL),
1339-
Button::with_text(button).styled(button_style),
1340-
false,
1341-
),
1342-
)
1343-
.with_value(value)
1344-
.with_description(description),
1345-
)?
1346-
} else {
1347-
// Single button.
1348-
LayoutObj::new(
1349-
IconDialog::new(
1350-
icon,
1351-
title,
1352-
theme::button_bar(Button::with_text(button).styled(button_style).map(|msg| {
1353-
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
1354-
})),
1355-
)
1356-
.with_value(value)
1357-
.with_description(description),
1358-
)?
1315+
let obj = match button {
1316+
None => {
1317+
if time_ms == 0 {
1318+
// No buttons and no timer, used when we only want to draw the dialog once and
1319+
// then throw away the layout object.
1320+
LayoutObj::new(
1321+
IconDialog::new(icon, title, Empty)
1322+
.with_value(value)
1323+
.with_description(description),
1324+
)?
1325+
} else {
1326+
// Timeout, no buttons.
1327+
LayoutObj::new(
1328+
IconDialog::new(
1329+
icon,
1330+
title,
1331+
Timeout::new(time_ms).map(|_| Some(CancelConfirmMsg::Confirmed)),
1332+
)
1333+
.with_value(value)
1334+
.with_description(description),
1335+
)?
1336+
}
1337+
}
1338+
Some(button) => {
1339+
if allow_cancel {
1340+
// Two buttons.
1341+
LayoutObj::new(
1342+
IconDialog::new(
1343+
icon,
1344+
title,
1345+
Button::cancel_confirm(
1346+
Button::with_icon(theme::ICON_CANCEL),
1347+
Button::with_text(button).styled(button_style),
1348+
false,
1349+
),
1350+
)
1351+
.with_value(value)
1352+
.with_description(description),
1353+
)?
1354+
} else {
1355+
// Single button.
1356+
LayoutObj::new(
1357+
IconDialog::new(
1358+
icon,
1359+
title,
1360+
theme::button_bar(Button::with_text(button).styled(button_style).map(
1361+
|msg| {
1362+
(matches!(msg, ButtonMsg::Clicked))
1363+
.then(|| CancelConfirmMsg::Confirmed)
1364+
},
1365+
)),
1366+
)
1367+
.with_value(value)
1368+
.with_description(description),
1369+
)?
1370+
}
1371+
}
13591372
};
1360-
13611373
Ok(obj)
13621374
}
13631375

core/embed/rust/src/ui/layout_caesar/ui_firmware.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,7 @@ impl FirmwareUI for UICaesar {
11731173
fn show_info(
11741174
title: TString<'static>,
11751175
description: TString<'static>,
1176-
_button: TString<'static>,
1176+
_button: Option<(TString<'static>, bool)>,
11771177
time_ms: u32,
11781178
) -> Result<Gc<LayoutObj>, Error> {
11791179
let content = Frame::new(

core/embed/rust/src/ui/layout_delizia/ui_firmware.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ impl FirmwareUI for UIDelizia {
971971
fn show_info(
972972
title: TString<'static>,
973973
description: TString<'static>,
974-
_button: TString<'static>,
974+
_button: Option<(TString<'static>, bool)>,
975975
_time_ms: u32,
976976
) -> Result<Gc<LayoutObj>, Error> {
977977
let content = Paragraphs::new(Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, description));

core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ impl ActionBar {
7979
/// paginated content.
8080
pub fn new_single(button: Button) -> Self {
8181
let mut right_button = button.with_expanded_touch_area(Self::BUTTON_EXPAND_TOUCH);
82-
if right_button.stylesheet() == &theme::button_default() {
82+
// If the button is disabled, don't override its stylesheet.
83+
if right_button.is_enabled() && right_button.stylesheet() == &theme::button_default() {
8384
right_button = right_button.styled(theme::firmware::button_actionbar_right_default());
8485
};
8586
if !right_button.has_gradient() {

core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,15 +1233,18 @@ impl FirmwareUI for UIEckhart {
12331233
fn show_info(
12341234
title: TString<'static>,
12351235
description: TString<'static>,
1236-
button: TString<'static>,
1236+
button: Option<(TString<'static>, bool)>,
12371237
_time_ms: u32,
12381238
) -> Result<Gc<LayoutObj>, Error> {
12391239
let content = Paragraphs::new(Paragraph::new(&theme::TEXT_REGULAR, description))
12401240
.with_placement(LinearPlacement::vertical());
12411241

1242+
let button = button.map_or_else(Button::empty, |(text, enabled)| {
1243+
Button::with_text(text).initially_enabled(enabled)
1244+
});
12421245
let screen = TextScreen::new(content)
12431246
.with_header(Header::new(title))
1244-
.with_action_bar(ActionBar::new_single(Button::with_text(button)));
1247+
.with_action_bar(ActionBar::new_single(button));
12451248
let obj = LayoutObj::new(screen)?;
12461249
Ok(obj)
12471250
}

core/embed/rust/src/ui/ui_firmware.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ pub trait FirmwareUI {
385385
fn show_info(
386386
title: TString<'static>,
387387
description: TString<'static>,
388-
button: TString<'static>,
388+
button: Option<(TString<'static>, bool)>,
389389
time_ms: u32,
390390
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
391391

core/mocks/generated/trezorui_api.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ def show_info(
691691
*,
692692
title: str,
693693
description: str = "",
694-
button: str = "",
694+
button: tuple[str, bool] | None = None,
695695
time_ms: int = 0,
696696
) -> LayoutObj[UiResult]:
697697
"""Info screen."""

core/src/trezor/ui/layouts/bolt/reset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ def show_intro_backup(num_of_words: int | None) -> Awaitable[None]:
289289
trezorui_api.show_info(
290290
title="",
291291
description=description,
292-
button=TR.buttons__continue,
292+
button=(TR.buttons__continue, True),
293293
),
294294
"backup_intro",
295295
ButtonRequestType.ResetDevice,
@@ -301,7 +301,7 @@ def show_warning_backup() -> Awaitable[trezorui_api.UiResult]:
301301
trezorui_api.show_info(
302302
title=TR.reset__never_make_digital_copy,
303303
description="",
304-
button=TR.buttons__ok_i_understand,
304+
button=(TR.buttons__ok_i_understand, True),
305305
),
306306
"backup_warning",
307307
ButtonRequestType.ResetDevice,

core/src/trezor/ui/layouts/eckhart/reset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ async def show_intro_backup(num_of_words: int | None) -> None:
316316
trezorui_api.show_info(
317317
title=TR.reset__recovery_wallet_backup_title,
318318
description=description,
319-
button=TR.buttons__continue,
319+
button=(TR.buttons__continue, True),
320320
),
321321
"backup_intro",
322322
ButtonRequestType.ResetDevice,

0 commit comments

Comments
 (0)