refactor(delizia): mark cancel menu buttons
What changed, and why it matters
This commit is a code cleanup in the user-interface code for the Trezor hardware wallet's 'delizia' layout. It adds a way to mark on-screen cancel buttons as 'cancel' buttons, primarily so automated testing/debug tools can identify them. It does not change what the buttons do or introduce any security-relevant behavior.
No security action required. This is a non-functional refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors how cancel menu items are created in the Delizia UI. A new is_cancel flag is added to the Button struct and exposed via the trace/debug interface. A new VerticalMenu::cancel_item() helper is introduced that creates a cancel-styled button and marks it with set_is_cancel(). Existing flows are updated to call cancel_item() instead of the generic danger() builder. This is purely a labeling/testing aid and does not alter runtime behavior, event handling, or security logic.
Changed components
core/embed/rust/src/ui/layout_delizia/component/button.rscore/embed/rust/src/ui/layout_delizia/component/vertical_menu.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_action.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_fido.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_firmware_update.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_homescreen.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_output.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_reset.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_set_new_code.rscore/embed/rust/src/ui/layout_delizia/flow/confirm_summary.rscore/embed/rust/src/ui/layout_delizia/flow/continue_recovery_homepage.rscore/embed/rust/src/ui/layout_delizia/flow/prompt_backup.rscore/embed/rust/src/ui/layout_delizia/flow/receive.rscore/embed/rust/src/ui/layout_delizia/flow/show_danger.rscore/embed/rust/src/ui/layout_delizia/flow/show_tutorial.rsInspect captured patch +37 / −35
diff --git a/core/embed/rust/src/ui/layout_delizia/component/button.rs b/core/embed/rust/src/ui/layout_delizia/component/button.rs
index 10bce619..af95654d 100644
--- a/core/embed/rust/src/ui/layout_delizia/component/button.rs
+++ b/core/embed/rust/src/ui/layout_delizia/component/button.rs
@@ -33,6 +33,7 @@ pub struct Button {
long_press: ShortDuration, // long press requires non-zero duration
long_timer: Timer,
haptic: bool,
+ is_cancel: bool, // used by debuglink
}
impl Button {
@@ -53,6 +54,7 @@ impl Button {
long_press: ShortDuration::ZERO,
long_timer: Timer::new(),
haptic: true,
+ is_cancel: false,
}
}
@@ -103,6 +105,11 @@ impl Button {
self
}
+ pub fn set_is_cancel(mut self) -> Self {
+ self.is_cancel = true;
+ self
+ }
+
pub fn enable_if(&mut self, ctx: &mut EventCtx, enabled: bool) {
if enabled {
self.enable(ctx);
@@ -361,6 +368,7 @@ impl Component for Button {
impl crate::trace::Trace for Button {
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("Button");
+ t.bool("is_cancel", self.is_cancel);
match &self.content {
ButtonContent::Empty => {}
ButtonContent::Text(text) => t.string("text", *text),
diff --git a/core/embed/rust/src/ui/layout_delizia/component/vertical_menu.rs b/core/embed/rust/src/ui/layout_delizia/component/vertical_menu.rs
index 0d910d30..08f0d491 100644
--- a/core/embed/rust/src/ui/layout_delizia/component/vertical_menu.rs
+++ b/core/embed/rust/src/ui/layout_delizia/component/vertical_menu.rs
@@ -208,7 +208,12 @@ impl VerticalMenu {
self
}
- pub fn danger(mut self, icon: Icon, text: TString<'static>) -> Self {
+ pub fn cancel_item(mut self, text: TString<'static>) -> Self {
+ unwrap!(self.buttons.push(VerticalMenuItem::Cancel(text).button()));
+ self
+ }
+
+ pub fn danger_item(mut self, icon: Icon, text: TString<'static>) -> Self {
unwrap!(self.buttons.push(
Button::with_icon_and_text(IconText::new(text, icon))
.styled(theme::button_warning_high())
@@ -333,7 +338,9 @@ impl VerticalMenuItem {
}
VerticalMenuItem::Cancel(text) => {
let content = IconText::new(*text, theme::ICON_CANCEL);
- Button::with_icon_and_text(content).styled(theme::button_warning_high())
+ Button::with_icon_and_text(content)
+ .styled(theme::button_warning_high())
+ .set_is_cancel()
}
}
}
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_action.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_action.rs
index e3ffc233..1ada3437 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_action.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_action.rs
@@ -392,7 +392,7 @@ fn create_menu(
unwrap!(menu_items.push(MENU_ITEM_INFO));
}
- menu = menu.danger(theme::ICON_CANCEL, menu_strings.verb_cancel);
+ menu = menu.cancel_item(menu_strings.verb_cancel);
unwrap!(menu_items.push(MENU_ITEM_CANCEL));
let content_menu = Frame::left_aligned("".into(), menu).with_cancel_button();
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_fido.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_fido.rs
index 2c83ab1c..9b317ae2 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_fido.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_fido.rs
@@ -168,7 +168,7 @@ pub fn new_confirm_fido(
let content_menu = Frame::left_aligned(
"".into(),
- VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()),
+ VerticalMenu::empty().cancel_item(TR::buttons__cancel.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_firmware_update.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_firmware_update.rs
index a8d72d99..c350d82b 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_firmware_update.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_firmware_update.rs
@@ -77,7 +77,7 @@ pub fn new_confirm_firmware_update(
theme::ICON_CHEVRON_RIGHT,
TR::firmware_update__title_fingerprint.into(),
)
- .danger(theme::ICON_CANCEL, TR::buttons__cancel.into()),
+ .cancel_item(TR::buttons__cancel.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_homescreen.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_homescreen.rs
index 0b290761..5ecf41c9 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_homescreen.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_homescreen.rs
@@ -12,10 +12,7 @@ use crate::{
},
};
-use super::super::{
- component::{Frame, PromptScreen, SwipeContent, VerticalMenu},
- theme,
-};
+use super::super::component::{Frame, PromptScreen, SwipeContent, VerticalMenu};
/// Flow for a setting of homescreen wallpaper showing a preview of the image,
/// menu to cancel and tap to confirm prompt.
@@ -65,7 +62,7 @@ pub fn new_confirm_homescreen(
let content_menu = Frame::left_aligned(
TString::empty(),
- VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()),
+ VerticalMenu::empty().cancel_item(TR::buttons__cancel.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_output.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_output.rs
index 04de0b27..e2a08d0b 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_output.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_output.rs
@@ -230,10 +230,7 @@ pub fn new_confirm_output(
);
unwrap!(main_menu_items.push(MENU_ITEM_ACCOUNT_INFO));
}
- main_menu = main_menu.danger(
- theme::ICON_CANCEL,
- cancel_text.unwrap_or(TR::send__cancel_sign.into()),
- );
+ main_menu = main_menu.cancel_item(cancel_text.unwrap_or(TR::send__cancel_sign.into()));
unwrap!(main_menu_items.push(MENU_ITEM_CANCEL));
let content_main_menu = Frame::left_aligned(TString::empty(), main_menu)
.with_cancel_button()
@@ -298,10 +295,8 @@ pub fn new_confirm_output(
);
unwrap!(summary_menu_items.push(MENU_ITEM_FEE_INFO));
}
- summary_menu = summary_menu.danger(
- theme::ICON_CANCEL,
- cancel_text.unwrap_or(TR::send__cancel_sign.into()),
- );
+ summary_menu =
+ summary_menu.cancel_item(cancel_text.unwrap_or(TR::send__cancel_sign.into()));
unwrap!(summary_menu_items.push(MENU_ITEM_CANCEL));
let content_summary_menu = Frame::left_aligned(TString::empty(), summary_menu)
.with_cancel_button()
@@ -313,10 +308,8 @@ pub fn new_confirm_output(
});
// HoldMenu
- let hold_menu = VerticalMenu::empty().danger(
- theme::ICON_CANCEL,
- cancel_text.unwrap_or(TR::send__cancel_sign.into()),
- );
+ let hold_menu =
+ VerticalMenu::empty().cancel_item(cancel_text.unwrap_or(TR::send__cancel_sign.into()));
let content_hold_menu = Frame::left_aligned(TString::empty(), hold_menu)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_reset.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_reset.rs
index 92a14411..8ad9dfa5 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_reset.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_reset.rs
@@ -114,7 +114,7 @@ pub fn new_confirm_reset(recovery: bool) -> Result<SwipeFlow, error::Error> {
let content_menu = Frame::left_aligned(
TString::empty(),
- VerticalMenu::empty().danger(theme::ICON_CANCEL, cancel_btn_text),
+ VerticalMenu::empty().cancel_item(cancel_btn_text),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_set_new_code.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_set_new_code.rs
index 61f990f8..2642f244 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_set_new_code.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_set_new_code.rs
@@ -80,7 +80,7 @@ pub fn new_set_new_code(is_wipe_code: bool) -> Result<SwipeFlow, error::Error> {
let content_menu = Frame::left_aligned(
"".into(),
- VerticalMenu::empty().danger(theme::ICON_CANCEL, cancel_menu_item.into()),
+ VerticalMenu::empty().cancel_item(cancel_menu_item.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/confirm_summary.rs b/core/embed/rust/src/ui/layout_delizia/flow/confirm_summary.rs
index 15ce8b0b..b828259b 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/confirm_summary.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/confirm_summary.rs
@@ -114,10 +114,7 @@ pub fn new_confirm_summary(
);
unwrap!(menu_items.push(MENU_ITEM_ACCOUNT_INFO));
}
- menu = menu.danger(
- theme::ICON_CANCEL,
- verb_cancel.unwrap_or(TR::send__cancel_sign.into()),
- );
+ menu = menu.cancel_item(verb_cancel.unwrap_or(TR::send__cancel_sign.into()));
unwrap!(menu_items.push(MENU_ITEM_CANCEL));
let content_menu = Frame::left_aligned(TString::empty(), menu)
.with_cancel_button()
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/continue_recovery_homepage.rs b/core/embed/rust/src/ui/layout_delizia/flow/continue_recovery_homepage.rs
index 210db71c..f500444e 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/continue_recovery_homepage.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/continue_recovery_homepage.rs
@@ -214,7 +214,7 @@ pub fn new_continue_recovery_homepage(
let res = if show_instructions {
let content_menu = Frame::left_aligned(
TString::empty(),
- VerticalMenu::empty().danger(theme::ICON_CANCEL, cancel_btn.into()),
+ VerticalMenu::empty().cancel_item(cancel_btn.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
@@ -231,7 +231,7 @@ pub fn new_continue_recovery_homepage(
theme::ICON_CHEVRON_RIGHT,
TR::recovery__title_remaining_shares.into(),
)
- .danger(theme::ICON_CANCEL, cancel_btn.into()),
+ .cancel_item(cancel_btn.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
@@ -281,7 +281,7 @@ pub fn new_continue_recovery_homepage(
} else {
let content_menu = Frame::left_aligned(
TString::empty(),
- VerticalMenu::empty().danger(theme::ICON_CANCEL, cancel_btn.into()),
+ VerticalMenu::empty().cancel_item(cancel_btn.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/prompt_backup.rs b/core/embed/rust/src/ui/layout_delizia/flow/prompt_backup.rs
index 64ad8dc6..7f4e9026 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/prompt_backup.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/prompt_backup.rs
@@ -68,7 +68,7 @@ pub fn new_prompt_backup() -> Result<SwipeFlow, error::Error> {
let content_menu = Frame::left_aligned(
"".into(),
- VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::backup__title_skip.into()),
+ VerticalMenu::empty().cancel_item(TR::backup__title_skip.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/receive.rs b/core/embed/rust/src/ui/layout_delizia/flow/receive.rs
index 799bf345..aae03e6e 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/receive.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/receive.rs
@@ -135,7 +135,7 @@ pub fn new_receive(
theme::ICON_CHEVRON_RIGHT,
TR::address_details__account_info.into(),
)
- .danger(theme::ICON_CANCEL, cancel_title.into()),
+ .cancel_item(cancel_title.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/show_danger.rs b/core/embed/rust/src/ui/layout_delizia/flow/show_danger.rs
index 2dd0863b..736f1934 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/show_danger.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/show_danger.rs
@@ -80,7 +80,7 @@ pub fn new_show_danger(
"".into(),
VerticalMenu::empty()
.item(theme::ICON_CANCEL, verb_cancel)
- .danger(theme::ICON_CHEVRON_RIGHT, confirm),
+ .danger_item(theme::ICON_CHEVRON_RIGHT, confirm),
)
.with_cancel_button()
.map(super::util::map_to_choice);
diff --git a/core/embed/rust/src/ui/layout_delizia/flow/show_tutorial.rs b/core/embed/rust/src/ui/layout_delizia/flow/show_tutorial.rs
index 86e06f6f..046da10d 100644
--- a/core/embed/rust/src/ui/layout_delizia/flow/show_tutorial.rs
+++ b/core/embed/rust/src/ui/layout_delizia/flow/show_tutorial.rs
@@ -133,7 +133,7 @@ pub fn new_show_tutorial() -> Result<SwipeFlow, error::Error> {
VerticalMenu::empty()
.item(theme::ICON_CHEVRON_RIGHT, TR::tutorial__did_you_know.into())
.item(theme::ICON_REBOOT, TR::tutorial__restart_tutorial.into())
- .danger(theme::ICON_CANCEL, TR::tutorial__exit.into()),
+ .cancel_item(TR::tutorial__exit.into()),
)
.with_cancel_button()
.map(super::util::map_to_choice);
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.