chore(core/eckhart): update tutorial screen
What changed, and why it matters
This commit is a routine user-interface refresh for the Trezor Safe 7 tutorial. It replaces some tutorial text, adds new icons, and extracts the screen background drawing into a reusable component. There is no security-relevant change visible in the code.
No security action required. Treat as normal UI maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors the Eckhart layout tutorial and homescreen background rendering. A new ScreenBackground component is introduced in theme/background.rs and used by Homescreen, TextScreen, and the tutorial flow. The tutorial welcome screen now uses a stopwatch-based loader animation and an optional RGB LED color change. Translation keys for TROPIC01 tutorial text are consolidated and new strings added. UI test fixtures are updated accordingly. No cryptographic, authentication, or memory-safety changes are present.
Changed components
core/embed/rust/src/ui/layout_eckhart/firmware/tutorial_screen.rscore/embed/rust/src/ui/layout_eckhart/firmware/homescreen.rscore/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rscore/embed/rust/src/ui/layout_eckhart/flow/show_tutorial.rscore/embed/rust/src/ui/layout_eckhart/theme/background.rscore/embed/rust/src/ui/layout_eckhart/theme/gradient.rscore/embed/rust/src/ui/layout_eckhart/theme/mod.rscore/translations/en.jsontests/click_tests/test_tutorial_eckhart.pytests/ui_tests/fixtures.jsonInspect captured patch +236 / −145
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index 285f3230..3b9466d0 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -812,6 +812,7 @@ static void _librust_qstrs(void) {
MP_QSTR_tutorial__suite_restart;
MP_QSTR_tutorial__sure_you_want_skip;
MP_QSTR_tutorial__swipe_up_and_down;
+ MP_QSTR_tutorial__tap_to_start;
MP_QSTR_tutorial__title_easy_navigation;
MP_QSTR_tutorial__title_handy_menu;
MP_QSTR_tutorial__title_hello;
@@ -821,10 +822,7 @@ static void _librust_qstrs(void) {
MP_QSTR_tutorial__title_skip;
MP_QSTR_tutorial__title_tutorial_complete;
MP_QSTR_tutorial__title_well_done;
- MP_QSTR_tutorial__tropic;
- MP_QSTR_tutorial__tropic_info1;
- MP_QSTR_tutorial__tropic_info2;
- MP_QSTR_tutorial__tropic_info3;
+ MP_QSTR_tutorial__tropic_info;
MP_QSTR_tutorial__use_trezor;
MP_QSTR_tutorial__welcome_press_right;
MP_QSTR_tutorial__welcome_safe5;
diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs
index f646b256..2c8e2270 100644
--- a/core/embed/rust/src/translations/generated/translated_string.rs
+++ b/core/embed/rust/src/translations/generated/translated_string.rs
@@ -1459,12 +1459,10 @@ pub enum TranslatedString {
tutorial__menu_appendix = 1060, // "View more info, quit flow, ..."
tutorial__navigation_ts7 = 1061, // "Use buttons at the bottom to navigate and confirm your actions."
tutorial__suite_restart = 1062, // "Replay this tutorial anytime from the Trezor Suite app."
- tutorial__tropic = 1063, // "Secured with TROPIC01"
- tutorial__tropic_info1 = 1064, // "TROPIC01 is a next-gen secure element with tamper-proof protection and open architecture."
- tutorial__tropic_info2 = 1065, // "Private keys stay on-chip, safeguarded by hardware-enforced boundaries and anti-tamper tech."
- tutorial__tropic_info3 = 1066, // "Built for security from the ground up, and open to independent audits."
- tutorial__welcome_safe7 = 1067, // "Welcome to\nTrezor\nSafe 7"
+ tutorial__welcome_safe7 = 1067, // "Welcome\nto Trezor\nSafe 7"
tutorial__what_is_tropic = 1068, // "What is TROPIC01?"
+ tutorial__tap_to_start = 1069, // "Tap to start tutorial"
+ tutorial__tropic_info = 1070, // "TROPIC01 is a next-gen open-source secure element chip designed for transparent and auditable hardware security."
}
impl TranslatedString {
@@ -3243,12 +3241,10 @@ impl TranslatedString {
(Self::tutorial__menu_appendix, "View more info, quit flow, ..."),
(Self::tutorial__navigation_ts7, "Use buttons at the bottom to navigate and confirm your actions."),
(Self::tutorial__suite_restart, "Replay this tutorial anytime from the Trezor Suite app."),
- (Self::tutorial__tropic, "Secured with TROPIC01"),
- (Self::tutorial__tropic_info1, "TROPIC01 is a next-gen secure element with tamper-proof protection and open architecture."),
- (Self::tutorial__tropic_info2, "Private keys stay on-chip, safeguarded by hardware-enforced boundaries and anti-tamper tech."),
- (Self::tutorial__tropic_info3, "Built for security from the ground up, and open to independent audits."),
- (Self::tutorial__welcome_safe7, "Welcome to\nTrezor\nSafe 7"),
+ (Self::tutorial__welcome_safe7, "Welcome\nto Trezor\nSafe 7"),
(Self::tutorial__what_is_tropic, "What is TROPIC01?"),
+ (Self::tutorial__tap_to_start, "Tap to start tutorial"),
+ (Self::tutorial__tropic_info, "TROPIC01 is a next-gen open-source secure element chip designed for transparent and auditable hardware security."),
];
#[cfg(feature = "micropython")]
@@ -4594,6 +4590,7 @@ impl TranslatedString {
(Qstr::MP_QSTR_tutorial__suite_restart, Self::tutorial__suite_restart),
(Qstr::MP_QSTR_tutorial__sure_you_want_skip, Self::tutorial__sure_you_want_skip),
(Qstr::MP_QSTR_tutorial__swipe_up_and_down, Self::tutorial__swipe_up_and_down),
+ (Qstr::MP_QSTR_tutorial__tap_to_start, Self::tutorial__tap_to_start),
(Qstr::MP_QSTR_tutorial__title_easy_navigation, Self::tutorial__title_easy_navigation),
(Qstr::MP_QSTR_tutorial__title_handy_menu, Self::tutorial__title_handy_menu),
(Qstr::MP_QSTR_tutorial__title_hello, Self::tutorial__title_hello),
@@ -4603,10 +4600,7 @@ impl TranslatedString {
(Qstr::MP_QSTR_tutorial__title_skip, Self::tutorial__title_skip),
(Qstr::MP_QSTR_tutorial__title_tutorial_complete, Self::tutorial__title_tutorial_complete),
(Qstr::MP_QSTR_tutorial__title_well_done, Self::tutorial__title_well_done),
- (Qstr::MP_QSTR_tutorial__tropic, Self::tutorial__tropic),
- (Qstr::MP_QSTR_tutorial__tropic_info1, Self::tutorial__tropic_info1),
- (Qstr::MP_QSTR_tutorial__tropic_info2, Self::tutorial__tropic_info2),
- (Qstr::MP_QSTR_tutorial__tropic_info3, Self::tutorial__tropic_info3),
+ (Qstr::MP_QSTR_tutorial__tropic_info, Self::tutorial__tropic_info),
(Qstr::MP_QSTR_tutorial__use_trezor, Self::tutorial__use_trezor),
(Qstr::MP_QSTR_tutorial__welcome_press_right, Self::tutorial__welcome_press_right),
(Qstr::MP_QSTR_tutorial__welcome_safe5, Self::tutorial__welcome_safe5),
diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/homescreen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/homescreen.rs
index a4e9bb1b..b2621089 100644
--- a/core/embed/rust/src/ui/layout_eckhart/firmware/homescreen.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/firmware/homescreen.rs
@@ -10,7 +10,7 @@ use crate::{
ui::{
component::{text::TextStyle, Component, Event, EventCtx, Label, Never, Swipe},
display::{image::ImageInfo, Color},
- geometry::{Alignment, Alignment2D, Direction, Insets, Offset, Rect},
+ geometry::{Alignment, Direction, Insets, Offset, Rect},
layout::util::get_user_custom_image,
shape::{self, Renderer},
util::animation_disabled,
@@ -23,7 +23,7 @@ use super::{
fonts,
},
constant::{HEIGHT, SCREEN, WIDTH},
- theme::{self, firmware::button_homebar_style, Gradient, TILES_GRID},
+ theme::{self, firmware::button_homebar_style, ScreenBackground},
ActionBar, ActionBarMsg, Hint,
};
@@ -164,37 +164,6 @@ impl Homescreen {
}
false
}
-
- fn render_default_hs<'s>(&self, target: &mut impl Renderer<'s>) {
- // Layer 1: Base Solid Colour
- shape::Bar::new(SCREEN)
- .with_bg(theme::GREY_EXTRA_DARK)
- .render(target);
-
- // Layer 2: Base Gradient overlay
- Gradient::HomescreenBase.render(target, SCREEN, 1);
-
- // Layer 3: (Optional) LED lightning simulation
- if let Some(led_color) = self.led_color {
- let gradient_area = SCREEN.inset(Insets::bottom(theme::ACTION_BAR_HEIGHT));
- Gradient::HomescreenLEDSim(led_color).render(target, gradient_area, 1);
- }
-
- // Layer 4: Tile pattern
- // TODO: improve frame rate
- for idx in 0..TILES_GRID.cell_count() {
- let tile_area = TILES_GRID.cell(idx);
- let icon = if theme::TILES_SLASH_INDICES.contains(&idx) {
- theme::ICON_TILE_STRIPES_SLASH.toif
- } else {
- theme::ICON_TILE_STRIPES_BACKSLASH.toif
- };
- shape::ToifImage::new(tile_area.top_left(), icon)
- .with_align(Alignment2D::TOP_LEFT)
- .with_fg(theme::BLACK)
- .render(target);
- }
- }
}
impl Drop for Homescreen {
@@ -266,7 +235,7 @@ impl Component for Homescreen {
shape::JpegImage::new_image(SCREEN.top_left(), image).render(target);
}
} else {
- self.render_default_hs(target);
+ ScreenBackground::new(self.led_color, None).render(target);
}
self.label.render(target);
self.hint.render(target);
diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs
index c07fa2b1..dd970a68 100644
--- a/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/firmware/text_screen.rs
@@ -18,7 +18,7 @@ use crate::{
};
use super::{
- theme::{self, SIDE_INSETS},
+ theme::{self, ScreenBackground, SIDE_INSETS},
ActionBar, ActionBarMsg, FidoAccountName, FidoCredential, Header, HeaderMsg, Hint,
};
@@ -37,6 +37,7 @@ pub struct TextScreen<T> {
hint: Option<Hint<'static>>,
action_bar: Option<ActionBar>,
page_limit: Option<u16>,
+ background: Option<ScreenBackground>,
// TODO: swipe handling
// TODO: animations
}
@@ -64,6 +65,7 @@ where
hint: None,
action_bar: Some(ActionBar::new_paginate_only()),
page_limit: None,
+ background: None,
}
}
@@ -94,6 +96,11 @@ where
self
}
+ pub fn with_background(mut self, background: ScreenBackground) -> Self {
+ self.background = Some(background);
+ self
+ }
+
fn update_page(&mut self, page_idx: u16) {
self.content.change_page(page_idx);
let pager = self.content_pager();
@@ -213,6 +220,9 @@ where
}
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
+ if let Some(background) = &self.background {
+ background.render(target);
+ }
self.header.render(target);
self.subtitle.render(target);
self.hint.render(target);
diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/tutorial_screen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/tutorial_screen.rs
index 79014331..9fb7215d 100644
--- a/core/embed/rust/src/ui/layout_eckhart/firmware/tutorial_screen.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/firmware/tutorial_screen.rs
@@ -1,25 +1,36 @@
use crate::{
- time::Duration,
+ time::{Duration, Stopwatch},
translations::TR,
ui::{
- component::{swipe_detect::SwipeConfig, Component, Event, EventCtx, Label},
+ component::{swipe_detect::SwipeConfig, Component, Event, EventCtx, Label, Timeout},
+ display::{toif::Toif, Color},
flow::Swipable,
- geometry::{Alignment, Insets, Rect},
- shape::Renderer,
+ geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect},
+ shape::{Renderer, ToifImage},
util::{animation_disabled, Pager},
},
};
-use super::super::{
- component::Button,
- constant::SCREEN,
- cshape::{render_loader_indeterminate, ScreenBorder},
- firmware::{ActionBar, ActionBarMsg},
- theme,
+#[cfg(feature = "rgb_led")]
+use crate::trezorhal::rgb_led;
+
+use super::{
+ super::{
+ component::Button,
+ constant::SCREEN,
+ cshape::{render_loader_indeterminate, ScreenBorder},
+ theme::{self, ScreenBackground},
+ },
+ ActionBar, ActionBarMsg,
};
-const LOADER_SPEED: u16 = 2;
-const ANIM_DURATION: Duration = Duration::from_secs(3);
+// Duration of the loader animation
+const LOADER_DURATION: Duration = Duration::from_secs(3);
+// Loader animation + gradient duration
+const TOTAL_DURATION: Duration = Duration::from_secs(5);
+const LOADER_MAX_VAL: u16 = 1000;
+const ICONS_PADDING: i16 = 15; // [px]
+const LED_COLOR: Color = theme::LED_WHITE;
pub enum TutorialWelcomeScreenMsg {
Confirmed,
@@ -28,8 +39,11 @@ pub enum TutorialWelcomeScreenMsg {
pub struct TutorialWelcomeScreen {
text: Label<'static>,
action_bar: ActionBar,
- /// Current value of the progress bar.
- value: u16,
+ /// Timer for the led color change
+ #[cfg(feature = "rgb_led")]
+ timer: Timeout,
+ /// Stopwatch for the loader animation
+ stopwatch: Stopwatch,
border: ScreenBorder,
}
@@ -42,11 +56,14 @@ impl TutorialWelcomeScreen {
theme::firmware::TEXT_REGULAR,
)
.top_aligned(),
- action_bar: ActionBar::new_timeout(
- Button::with_text(TR::tutorial__tropic.into()),
- ANIM_DURATION,
- ),
- value: 0,
+ action_bar: ActionBar::new_timeout(Button::empty(), TOTAL_DURATION),
+ #[cfg(feature = "rgb_led")]
+ timer: Timeout::new(if animation_disabled() {
+ 0
+ } else {
+ LOADER_DURATION.to_millis()
+ }),
+ stopwatch: Stopwatch::new_started(),
border: ScreenBorder::new(theme::GREEN_LIME),
}
}
@@ -69,9 +86,18 @@ impl Component for TutorialWelcomeScreen {
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
if let Some(ActionBarMsg::Confirmed) = self.action_bar.event(ctx, event) {
+ // Turn off the LED when the screen is destroyed
+ #[cfg(feature = "rgb_led")]
+ rgb_led::set_color(0);
return Some(TutorialWelcomeScreenMsg::Confirmed);
}
+ #[cfg(feature = "rgb_led")]
+ if self.timer.event(ctx, event).is_some() {
+ rgb_led::set_color(LED_COLOR.to_u32());
+ return None;
+ }
+
// TutorialWelcomeScreen reacts to ANIM_FRAME_TIMER
match event {
_ if animation_disabled() => {
@@ -81,7 +107,6 @@ impl Component for TutorialWelcomeScreen {
ctx.request_anim_frame();
}
Event::Timer(EventCtx::ANIM_FRAME_TIMER) => {
- self.value = (self.value + LOADER_SPEED) % 1000;
ctx.request_anim_frame();
ctx.request_paint();
}
@@ -91,10 +116,40 @@ impl Component for TutorialWelcomeScreen {
}
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
- let progress_val = self.value.min(1000);
+ const ICON_TROPIC: Toif<'static> = theme::ICON_TROPIC.toif;
+ // Center the icon in the action bar area in the full-screen component
+ const ICON_POS: Point = SCREEN
+ .bottom_center()
+ .ofs(Offset::new(0, -theme::ACTION_BAR_HEIGHT / 2));
+
+ if !self.stopwatch.is_running_within(LOADER_DURATION) {
+ ScreenBackground::new(Some(LED_COLOR), None).render(target);
+ }
+
self.text.render(target);
- self.action_bar.render(target);
- render_loader_indeterminate(progress_val, &self.border, target);
+
+ // Topic icon
+ ToifImage::new(ICON_POS, ICON_TROPIC)
+ .with_align(Alignment2D::CENTER)
+ .with_fg(theme::GREY_EXTRA_LIGHT)
+ .render(target);
+
+ // Intro icon
+ ToifImage::new(
+ ICON_POS
+ .sub(Point::new(0, ICONS_PADDING + ICON_TROPIC.height() / 2))
+ .into(),
+ theme::ICON_SECURED.toif,
+ )
+ .with_align(Alignment2D::BOTTOM_CENTER)
+ .with_fg(theme::GREY_EXTRA_LIGHT)
+ .render(target);
+
+ if self.stopwatch.is_running_within(LOADER_DURATION) {
+ let progress = self.stopwatch.elapsed() / LOADER_DURATION;
+ let loader_val = (progress * LOADER_MAX_VAL as f32) as u16;
+ render_loader_indeterminate(loader_val, &self.border, target);
+ }
}
}
diff --git a/core/embed/rust/src/ui/layout_eckhart/flow/show_tutorial.rs b/core/embed/rust/src/ui/layout_eckhart/flow/show_tutorial.rs
index 3718d835..047aa457 100644
--- a/core/embed/rust/src/ui/layout_eckhart/flow/show_tutorial.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/flow/show_tutorial.rs
@@ -22,11 +22,11 @@ use super::super::{
TutorialWelcomeScreen, TutorialWelcomeScreenMsg, VerticalMenu, VerticalMenuScreen,
VerticalMenuScreenMsg,
},
- theme::{self, Gradient},
+ theme::{self, Gradient, ScreenBackground},
};
const WELCOME_SCREEN_DURATION_MS: u32 = 3000;
-type TropicScreen = TextScreen<Paragraphs<[Paragraph<'static>; 3]>>;
+type TropicScreen = TextScreen<Paragraphs<Paragraph<'static>>>;
type TropicScreenMap = MsgMap<TropicScreen, fn(TextScreenMsg) -> Option<FlowMsg>>;
#[derive(Copy, Clone, PartialEq, Eq)]
@@ -90,12 +90,9 @@ impl FlowController for ShowTutorial {
fn content_tropic() -> TropicScreenMap {
TextScreen::new(
- Paragraphs::new([
- Paragraph::new(&theme::TEXT_REGULAR, TR::tutorial__tropic_info1).break_after(),
- Paragraph::new(&theme::TEXT_REGULAR, TR::tutorial__tropic_info2).break_after(),
- Paragraph::new(&theme::TEXT_REGULAR, TR::tutorial__tropic_info3),
- ])
- .with_placement(LinearPlacement::vertical()),
+ Paragraph::new(&theme::TEXT_REGULAR, TR::tutorial__tropic_info)
+ .into_paragraphs()
+ .with_placement(LinearPlacement::vertical()),
)
.with_header(Header::new(TR::tutorial__what_is_tropic.into()).with_close_button())
.map(|msg| match msg {
@@ -114,9 +111,10 @@ pub fn new_show_tutorial() -> Result<SwipeFlow, error::Error> {
.into_paragraphs()
.with_placement(LinearPlacement::vertical()),
)
- .with_action_bar(ActionBar::new_single(Button::with_text(
- TR::instructions__tap_to_start.into(),
- )))
+ .with_action_bar(ActionBar::new_single(Button::with_homebar_content(Some(
+ TR::tutorial__tap_to_start.into(),
+ ))))
+ .with_background(ScreenBackground::new(None, None))
.map(|msg| match msg {
TextScreenMsg::Confirmed => Some(FlowMsg::Confirmed),
_ => None,
diff --git a/core/embed/rust/src/ui/layout_eckhart/res/secured.png b/core/embed/rust/src/ui/layout_eckhart/res/secured.png
new file mode 100644
index 00000000..32eb486f
Binary files /dev/null and b/core/embed/rust/src/ui/layout_eckhart/res/secured.png differ
diff --git a/core/embed/rust/src/ui/layout_eckhart/res/secured.toif b/core/embed/rust/src/ui/layout_eckhart/res/secured.toif
new file mode 100644
index 00000000..39302496
Binary files /dev/null and b/core/embed/rust/src/ui/layout_eckhart/res/secured.toif differ
diff --git a/core/embed/rust/src/ui/layout_eckhart/res/tropic.png b/core/embed/rust/src/ui/layout_eckhart/res/tropic.png
new file mode 100644
index 00000000..e78267c9
Binary files /dev/null and b/core/embed/rust/src/ui/layout_eckhart/res/tropic.png differ
diff --git a/core/embed/rust/src/ui/layout_eckhart/res/tropic.toif b/core/embed/rust/src/ui/layout_eckhart/res/tropic.toif
new file mode 100644
index 00000000..ec21313c
Binary files /dev/null and b/core/embed/rust/src/ui/layout_eckhart/res/tropic.toif differ
diff --git a/core/embed/rust/src/ui/layout_eckhart/theme/background.rs b/core/embed/rust/src/ui/layout_eckhart/theme/background.rs
new file mode 100644
index 00000000..66553c6e
--- /dev/null
+++ b/core/embed/rust/src/ui/layout_eckhart/theme/background.rs
@@ -0,0 +1,63 @@
+use crate::ui::{
+ display::Color,
+ geometry::{Alignment2D, Insets},
+ shape::{self, Renderer},
+};
+
+use super::super::{
+ constant::SCREEN,
+ theme::{self, Gradient, TILES_GRID},
+};
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct ScreenBackground {
+ /// LED color for the simulation
+ led_color: Option<Color>,
+ /// Step size for the gradient (1 = full quality, higher = faster but lower
+ /// quality)
+ step_size: u16,
+}
+
+impl ScreenBackground {
+ pub fn new(led_color: Option<Color>, step_size: Option<u16>) -> Self {
+ Self {
+ led_color,
+ step_size: step_size.unwrap_or(1),
+ }
+ }
+
+ /// Renders the homescreen background
+ ///
+ /// # Arguments
+ /// * `target` - The renderer to draw to
+ pub fn render<'s>(&self, target: &mut impl Renderer<'s>) {
+ // Layer 1: Base Solid Colour
+ shape::Bar::new(SCREEN)
+ .with_bg(theme::GREY_EXTRA_DARK)
+ .render(target);
+
+ // Layer 2: Base Gradient overlay
+ Gradient::HomescreenBase.render(target, SCREEN, self.step_size);
+
+ if let Some(led_color) = self.led_color {
+ // Layer 3: (Optional) LED lightning simulation
+ let gradient_area = SCREEN.inset(Insets::bottom(theme::ACTION_BAR_HEIGHT));
+ Gradient::ScreenLEDSim(led_color).render(target, gradient_area, self.step_size);
+ }
+
+ // Layer 4: Tile pattern
+ // TODO: improve frame rate
+ for idx in 0..TILES_GRID.cell_count() {
+ let tile_area = TILES_GRID.cell(idx);
+ let icon = if theme::TILES_SLASH_INDICES.contains(&idx) {
+ theme::ICON_TILE_STRIPES_SLASH.toif
+ } else {
+ theme::ICON_TILE_STRIPES_BACKSLASH.toif
+ };
+ shape::ToifImage::new(tile_area.top_left(), icon)
+ .with_align(Alignment2D::TOP_LEFT)
+ .with_fg(theme::BLACK)
+ .render(target);
+ }
+ }
+}
diff --git a/core/embed/rust/src/ui/layout_eckhart/theme/gradient.rs b/core/embed/rust/src/ui/layout_eckhart/theme/gradient.rs
index 5ea86e64..d38ee6b1 100644
--- a/core/embed/rust/src/ui/layout_eckhart/theme/gradient.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/theme/gradient.rs
@@ -19,7 +19,7 @@ pub enum Gradient {
#[cfg(feature = "micropython")]
HomescreenBase,
#[cfg(feature = "micropython")]
- HomescreenLEDSim(Color),
+ ScreenLEDSim(Color),
}
impl Gradient {
@@ -52,7 +52,7 @@ fn render_gradient<'s>(
#[cfg(feature = "micropython")]
Gradient::HomescreenBase => render_homescreen_base(target, area, step_size),
#[cfg(feature = "micropython")]
- Gradient::HomescreenLEDSim(color) => render_led_simulation(target, area, step_size, color),
+ Gradient::ScreenLEDSim(color) => render_led_simulation(target, area, step_size, color),
}
}
diff --git a/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs b/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs
index 2c2f410d..8752a9cb 100644
--- a/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/theme/mod.rs
@@ -1,3 +1,5 @@
+#[cfg(feature = "micropython")]
+pub mod background;
pub mod backlight;
#[cfg(any(feature = "bootloader", feature = "prodtest"))]
pub mod bootloader;
@@ -15,7 +17,8 @@ use crate::ui::{
};
use super::fonts;
-
+#[cfg(feature = "micropython")]
+pub use background::ScreenBackground;
pub use gradient::Gradient;
// Color palette.
@@ -154,6 +157,10 @@ include_icon!(
// Icon for the bootup screen
include_icon!(ICON_SEVEN, "layout_eckhart/res/bootloader/7.toif");
+// Tutorial screen icons
+include_icon!(ICON_TROPIC, "layout_eckhart/res/tropic.toif");
+include_icon!(ICON_SECURED, "layout_eckhart/res/secured.toif");
+
// Common text styles and button styles must use fonts accessible from both
// bootloader and firmware
diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi
index d16b484f..9b6cf40a 100644
--- a/core/mocks/trezortranslate_keys.pyi
+++ b/core/mocks/trezortranslate_keys.pyi
@@ -933,6 +933,7 @@ class TR:
tutorial__suite_restart: str = "Replay this tutorial anytime from the Trezor Suite app."
tutorial__sure_you_want_skip: str = "Are you sure you\nwant to skip the tutorial?"
tutorial__swipe_up_and_down: str = "Tap the lower half of the screen to continue, or swipe down to go back."
+ tutorial__tap_to_start: str = "Tap to start tutorial"
tutorial__title_easy_navigation: str = "Easy navigation"
tutorial__title_handy_menu: str = "Handy menu"
tutorial__title_hello: str = "Hello"
@@ -942,14 +943,11 @@ class TR:
tutorial__title_skip: str = "Skip tutorial"
tutorial__title_tutorial_complete: str = "Tutorial complete"
tutorial__title_well_done: str = "Well done!"
- tutorial__tropic: str = "Secured with TROPIC01"
- tutorial__tropic_info1: str = "TROPIC01 is a next-gen secure element with tamper-proof protection and open architecture."
- tutorial__tropic_info2: str = "Private keys stay on-chip, safeguarded by hardware-enforced boundaries and anti-tamper tech."
- tutorial__tropic_info3: str = "Built for security from the ground up, and open to independent audits."
+ tutorial__tropic_info: str = "TROPIC01 is a next-gen open-source secure element chip designed for transparent and auditable hardware security."
tutorial__use_trezor: str = "Use Trezor by\nclicking the left and right buttons.\n\rContinue right."
tutorial__welcome_press_right: str = "Welcome to Trezor. Press right to continue."
tutorial__welcome_safe5: str = "Welcome to\nTrezor Safe 5"
- tutorial__welcome_safe7: str = "Welcome to\nTrezor\nSafe 7"
+ tutorial__welcome_safe7: str = "Welcome\nto Trezor\nSafe 7"
tutorial__what_is_tropic: str = "What is TROPIC01?"
u2f__get: str = "Increase and retrieve the U2F counter?"
u2f__set_template: str = "Set the U2F counter to {0}?"
diff --git a/core/translations/en.json b/core/translations/en.json
index ab6a5679..013c0225 100644
--- a/core/translations/en.json
+++ b/core/translations/en.json
@@ -1145,6 +1145,7 @@
"tutorial__suite_restart": "Replay this tutorial anytime from the Trezor Suite app.",
"tutorial__sure_you_want_skip": "Are you sure you\nwant to skip the tutorial?",
"tutorial__swipe_up_and_down": "Tap the lower half of the screen to continue, or swipe down to go back.",
+ "tutorial__tap_to_start": "Tap to start tutorial",
"tutorial__title_easy_navigation": "Easy navigation",
"tutorial__title_handy_menu": "Handy menu",
"tutorial__title_hello": "Hello",
@@ -1159,14 +1160,11 @@
"tutorial__title_skip": "Skip tutorial",
"tutorial__title_tutorial_complete": "Tutorial complete",
"tutorial__title_well_done": "Well done!",
- "tutorial__tropic": "Secured with TROPIC01",
- "tutorial__tropic_info1": "TROPIC01 is a next-gen secure element with tamper-proof protection and open architecture.",
- "tutorial__tropic_info2": "Private keys stay on-chip, safeguarded by hardware-enforced boundaries and anti-tamper tech.",
- "tutorial__tropic_info3": "Built for security from the ground up, and open to independent audits.",
+ "tutorial__tropic_info": "TROPIC01 is a next-gen open-source secure element chip designed for transparent and auditable hardware security.",
"tutorial__use_trezor": "Use Trezor by\nclicking the left and right buttons.\n\rContinue right.",
"tutorial__welcome_press_right": "Welcome to Trezor. Press right to continue.",
"tutorial__welcome_safe5": "Welcome to\nTrezor Safe 5",
- "tutorial__welcome_safe7": "Welcome to\nTrezor\nSafe 7",
+ "tutorial__welcome_safe7": "Welcome\nto Trezor\nSafe 7",
"tutorial__what_is_tropic": "What is TROPIC01?",
"u2f__get": "Increase and retrieve the U2F counter?",
"u2f__set_template": "Set the U2F counter to {0}?",
diff --git a/core/translations/order.json b/core/translations/order.json
index e46ef189..329d2dca 100644
--- a/core/translations/order.json
+++ b/core/translations/order.json
@@ -1067,5 +1067,7 @@
"1065": "tutorial__tropic_info2",
"1066": "tutorial__tropic_info3",
"1067": "tutorial__welcome_safe7",
- "1068": "tutorial__what_is_tropic"
+ "1068": "tutorial__what_is_tropic",
+ "1069": "tutorial__tap_to_start",
+ "1070": "tutorial__tropic_info"
}
diff --git a/core/translations/signatures.json b/core/translations/signatures.json
index 38bc04f3..087aa083 100644
--- a/core/translations/signatures.json
+++ b/core/translations/signatures.json
@@ -1,8 +1,8 @@
{
"current": {
- "merkle_root": "d3c8d2982597624b1f43859ba656c96b125922d24f153f3a56e2dc79af7ee55c",
- "datetime": "2025-08-08T17:21:54.566310+00:00",
- "commit": "e949774de068fc61cab79dc3316addf2aea4cc5d"
+ "merkle_root": "a974f788429324a9235ac786eed3d60ada3250eaae25c61d2fdd53462f271ab9",
+ "datetime": "2025-08-12T08:59:14.686679+00:00",
+ "commit": "a1dfa64d3fc5e6f1f9e7ff035eaa1d50d7abc392"
},
"history": [
{
diff --git a/tests/click_tests/test_tutorial_eckhart.py b/tests/click_tests/test_tutorial_eckhart.py
index 9b3faaca..f8b9c6c6 100644
--- a/tests/click_tests/test_tutorial_eckhart.py
+++ b/tests/click_tests/test_tutorial_eckhart.py
@@ -51,9 +51,7 @@ def _assert_tropic_info(debug: "DebugLink"):
layout = debug.read_layout()
assert layout.title() == TR.tutorial__what_is_tropic
text = _paginated_text(debug)
- assert TR.tutorial__tropic_info1 in text
- assert TR.tutorial__tropic_info2 in text
- assert TR.tutorial__tropic_info3 in text
+ assert TR.tutorial__tropic_info in text
debug.click(debug.screen_buttons.menu())
@@ -64,10 +62,9 @@ def _wait_for_welcome_animation(debug: "DebugLink"):
def _assert_begin_screen_and_proceed(debug: "DebugLink"):
- debug.synchronize_at(TR.instructions__tap_to_start)
layout = debug.read_layout()
assert layout.text_content() == TR.tutorial__welcome_safe7.replace("\n", " ")
- assert TR.instructions__tap_to_start in layout.action_bar()
+ assert TR.tutorial__tap_to_start in layout.action_bar()
debug.click(debug.screen_buttons.ok())
@@ -231,6 +228,7 @@ def test_tutorial_menu_tropic(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink()
device_handler.run_with_session(device.show_device_tutorial, seedless=True)
+ _wait_for_welcome_animation(debug)
_assert_begin_screen_and_proceed(debug)
_assert_navigation_screen_and_proceed(debug)
_assert_instructions_and_proceed_to_menu(debug)
@@ -286,6 +284,7 @@ def test_tutorial_restart(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink()
device_handler.run_with_session(device.show_device_tutorial, seedless=True)
+ _wait_for_welcome_animation(debug)
_assert_begin_screen_and_proceed(debug)
_assert_navigation_screen_and_proceed(debug)
_assert_instructions_and_proceed_to_menu(debug)
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 51a63b2a..417104e6 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -28437,12 +28437,12 @@
"T3W1_cs_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "d2f9ed0d66426d37be50ff4d7ed1f28d32cf3eee4216badc18067d232c31b46f",
"T3W1_cs_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "71e7429bc407b3e387bb6a73c521ebcc642b5e6f9887c84778870ea70e6519ef",
"T3W1_cs_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "e5a8c5832b7af4f6655962a48eec65c9aa3a23abb10aef15ba0297399f3d10de",
-"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "f01b897cd2e85f45a604f16000abd4af7cda4b17695c7231d9e0d72e7af16ac9",
-"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "c3cf70608f1f088f9696f71a9d53eff5b9c67ea3619da37ad6427d9c1a650b2f",
-"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_full_completion": "cf4b84b08650b6394cc1676aea6fa470aaa83783ed5c2debdb2d19bfbba0935d",
-"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_menu_close": "3486ffd208aa174460e6ca709456f69421918a31fa5fff3d4031ba20aa405d86",
-"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "55f8bbb5595a0fd2c07d001c992c5c5228bf7574d361abb21755f67553f06203",
-"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_restart": "bc545c91fd2d374f1771a9585c7e3bf754e30840b71cdd4539542dd5cca9d102",
+"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "0fc2b76688a6286f7d195f8d426ff527bafaaeeb1fe43c88e9a6602dac28e60f",
+"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "4755041b8293294b974abd5f458128838e10a2df562b363dd97bdf09b4c62f18",
+"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_full_completion": "e17d142bfb46db6cbfc8577b2c7a065c15ed60230a502f9ca55969b883fd9faf",
+"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_menu_close": "4e5f423f8ee00e7c1e20117b19245c9ea0b576898960ec7c85d88c069c9dc9b0",
+"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "b45d1aaad04bae910cfe4345751a8cc2e016c71aecbb443c088d4c4be8dc2e6c",
+"T3W1_cs_test_tutorial_eckhart.py::test_tutorial_restart": "362208e810cdc6e9b3cf6ff3e1770327b9f06395807c42896bfadb08ad99eb3e",
"T3W1_de_test_autolock.py::test_autolock_does_not_interrupt_signing": "f6ec7857738d46357863af87f2bd3bacba5b20989d389d88934f638a9197cc51",
"T3W1_de_test_autolock.py::test_autolock_interrupts_passphrase": "2bf88cb474ceece4441a51277297fc3d0e9c8c04d4083b2acb0d2848d1237c18",
"T3W1_de_test_autolock.py::test_autolock_interrupts_signing": "d3f21164e70220842a2a6c9f31a433558b7893b8b2d27f26475eeedea5001462",
@@ -28495,12 +28495,12 @@
"T3W1_de_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "858730668c17e18e346af887f13c55b3365983ebf4488b1207bc8a664716d644",
"T3W1_de_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "d631ea268219edb8894a796816d23666252ef86c91695e43082a8792fa360e2b",
"T3W1_de_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "1682fac984651e5cc03a5224b8bbfd647eafd7e29ad02662d11ac9e6dc280d91",
-"T3W1_de_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "c34ae0e42aaa382c8eda8cd812333d161ff86ba2d4aca85fc26edda646924088",
-"T3W1_de_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "4094d83068a149f8ad37c7b3772497613af1083d4d1c8eae3cbe4053c42c9f4c",
-"T3W1_de_test_tutorial_eckhart.py::test_tutorial_full_completion": "4b98f3c3f0e36f00ab60491ce44958a0eb47902aefec8194930fd773d79f6442",
-"T3W1_de_test_tutorial_eckhart.py::test_tutorial_menu_close": "25e5dec31af28a73acbc8bcc8f05b4416c15a29e8830a98d61c2156b333a531c",
-"T3W1_de_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "b4830e019dfe9280c6cd6f3f9f1b0a7b70c093ed7869e198c56c331e0ceeffda",
-"T3W1_de_test_tutorial_eckhart.py::test_tutorial_restart": "e178bd1327eb69953a257c4fec0a5de339b2f2186caa36cc46f52947c69eece6",
+"T3W1_de_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "5e0313b3799e0431b35cac24947f908dc11367a1ac937b59cb0a296c395759f5",
+"T3W1_de_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "ea4520351a6d90ea7599884bba0dc7e5359b8553b9e8b1374851d8aa67d7cc2e",
+"T3W1_de_test_tutorial_eckhart.py::test_tutorial_full_completion": "df2598d290796e722e7fc95267b07eeea51808c497473e0c788ae594c32d9bc5",
+"T3W1_de_test_tutorial_eckhart.py::test_tutorial_menu_close": "4e33682a244bea976c45b5ad9cde9922f01df1def480007e91af248b55323571",
+"T3W1_de_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "8f48f1bd54d257663cb3389d819e83523eec3f84914c5bb7f81c4be50ed8023e",
+"T3W1_de_test_tutorial_eckhart.py::test_tutorial_restart": "af650dde3931663eaabc7c828b04c55b8802b69255c8a2c124d3ed952ecfaaee",
"T3W1_en_test_autolock.py::test_autolock_does_not_interrupt_signing": "36477085887f2d9cc83d11680f03de8622ead10fbc3de2e08c27e3b3b0fb08ce",
"T3W1_en_test_autolock.py::test_autolock_interrupts_passphrase": "18194e4cc069c1d5c27cd71cbcb0230b6c724cf837633f043f1bee881304e99c",
"T3W1_en_test_autolock.py::test_autolock_interrupts_signing": "41e756aeba0854e36eb58fad71c24714bea073eb8e8991785dd320cc699b4ac0",
@@ -28553,12 +28553,12 @@
"T3W1_en_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "7050c27bca2318fc16f0836e37acc5a7c6a95d509df7ea89143b93023c1f5c8e",
"T3W1_en_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "99aac51ef17d2e1d3f1244d09fb603f5eb7407b299568233774112ca88e81569",
"T3W1_en_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "66ff09eab5c3b4dbc0323185c04699ba9716377c553d0c1390929493239d924d",
-"T3W1_en_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "921124257245998cdb0274df4b5e6f73e8d9b83f5122a070754098ff996ce2c4",
-"T3W1_en_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "4c171b2fd883bd450ca9e244149b505605396fcd527d11777f6164240dddab8b",
-"T3W1_en_test_tutorial_eckhart.py::test_tutorial_full_completion": "9c6454e5f146d75b1267ed21c4cada7b8d1d6bcf975f7072b4b54c1d1ba7ca92",
-"T3W1_en_test_tutorial_eckhart.py::test_tutorial_menu_close": "1f2e2faee59781c30e502e4bc4ba9909058cd261e0c57877b3937f2de1a5d678",
-"T3W1_en_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "03b24333c908bc1c0a4ce18bd393c93d0948780aee048ce58386b6aa221be992",
-"T3W1_en_test_tutorial_eckhart.py::test_tutorial_restart": "c8a6adb3a30a66ca4f6a9939ee046199ba6e957e7fb247034545ca5df9e3f35e",
+"T3W1_en_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "d38ca8a55980adef50cd8e68c8c6abce9639ac521498121b4c4f3655f106a1b6",
+"T3W1_en_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "d1f5affcf4572d62481a2cf38a341e9faec605cf391b86d87b90f1f348f8e83f",
+"T3W1_en_test_tutorial_eckhart.py::test_tutorial_full_completion": "bdc2cb972f844ffc757c6d0ec160a8105cea275ca856359661947c484a75e11c",
+"T3W1_en_test_tutorial_eckhart.py::test_tutorial_menu_close": "c7aca522b6bf1ef159aabc2caf034575959e77be22b3dee1e607300ef464c7a4",
+"T3W1_en_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "110f2a4afdbc9206666112ce3a9417b2e3458262a302f644d38593ba64e7ac2a",
+"T3W1_en_test_tutorial_eckhart.py::test_tutorial_restart": "b3c8bb5b8477c7059f5c02fa303b4b81264b0ec6e67e51c356e992b701419f30",
"T3W1_es_test_autolock.py::test_autolock_does_not_interrupt_signing": "ececf550d827f511b824619a62d25224293e25915e5b24c788331a5b2900f33d",
"T3W1_es_test_autolock.py::test_autolock_interrupts_passphrase": "a8c17fe88d988af14db8bf2a8b658955e69a4668e7584f2ac72df7031dc7c2e1",
"T3W1_es_test_autolock.py::test_autolock_interrupts_signing": "9e44a20e1a069f5d051ea4f1a0149ebf661fa550eee652867ceb5ff58e30f9f6",
@@ -28611,12 +28611,12 @@
"T3W1_es_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "abf166ffe5c36e97993a5dc019c195e9bf0da97d2c8aa588a65a92faa5ee8c69",
"T3W1_es_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "7a071c656fe63d0721eb0d60bc14bcbc1e4749742fa86bd0d00378cd0d745b82",
"T3W1_es_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "394963df28a03ddb9d94dda0c6779ef05bf60438eb449585b6cb8eb2a6461b6a",
-"T3W1_es_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "af3ade54711b7f11139b663bce4ee27ceb2de70afb59cdbae2df99b0e75c2e01",
-"T3W1_es_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "a3c26add3501a33c6815e51cf12fac588566f7b2157dba8dfd5c0cd6856af50f",
-"T3W1_es_test_tutorial_eckhart.py::test_tutorial_full_completion": "fd80c25b439aa55a15d77d6f26a2f0f99b9ecc326c91e2196d77c678e9892678",
-"T3W1_es_test_tutorial_eckhart.py::test_tutorial_menu_close": "383f672398aa0ba8f0bf129019c88622e9d8d9983a31b584a64e96ba9cd612d2",
-"T3W1_es_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "7fabded1286f7bb710c960ccc97eb39ffbefd282c4cc5c83cb1c12651fdfa859",
-"T3W1_es_test_tutorial_eckhart.py::test_tutorial_restart": "33ff565b0f3b36a1f8a45d02fdf0a1b5737fb1ea93b2be03ddc6eefb8cadcf0b",
+"T3W1_es_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "391c36faab034de31ac47513245ad9f4ab51639662f7011384969640be197c99",
+"T3W1_es_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "ffff9942118d643e2c5619da83cc176235374e2ee3ef328702a9d282f1128df3",
+"T3W1_es_test_tutorial_eckhart.py::test_tutorial_full_completion": "720f2b60508f984d7b9150426ece5406993e8a1f99e4cee9b401bfd908d4995c",
+"T3W1_es_test_tutorial_eckhart.py::test_tutorial_menu_close": "52ef770f13342f754bc713cbc25f3240e259d6a214bc905dae98f7eae4e4fd9b",
+"T3W1_es_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "6a4c9111cd126bf0c00d6c49740d5125fa06efb4585537d1cdc12a1e0673d067",
+"T3W1_es_test_tutorial_eckhart.py::test_tutorial_restart": "d5fe4ea120812c2b4b757fd87680146961cd571c88eb049b609b5b6fc3559914",
"T3W1_fr_test_autolock.py::test_autolock_does_not_interrupt_signing": "68e256ec382479c5e56e76ab26c51a60ee045fc580c4108e4e595828b191f229",
"T3W1_fr_test_autolock.py::test_autolock_interrupts_passphrase": "82077d2931ddb9c1282a6e8bb4e72dd46c97faaf86a70e049fba373d82b97a4e",
"T3W1_fr_test_autolock.py::test_autolock_interrupts_signing": "d9ecd06d3e3e9b219a92d22ace6e1af3e86060359cd076c022112d68351db8b4",
@@ -28669,12 +28669,12 @@
"T3W1_fr_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "e28279387a635bd8dd9f5c9eab1deed52f5b771eda0eb2b8d1701f68c8c6d82b",
"T3W1_fr_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "0777b9d9eb82490baffdd079497d5ecb6723b0e98989b0ba125fd3d8aacfa1a6",
"T3W1_fr_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "b15a2b032fea749de45e7482f48eac16c440acdaf248185c614cacead55d7fa1",
-"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "20aeda575f37330945574b5939794ce274b03d227d09f49960706bf1e2af6872",
-"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "d11005e393a228279fc33b9bcf3f16c1a953fe8731e8c0137c9ad59753e3ae16",
-"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_full_completion": "f74e475ca7c9651fd38ed277494784689cf4b37ab8ad371157b64bc0d4534cdb",
-"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_menu_close": "76f364e15aa0f3802230cb0a847eda481c71be4e97147f85a54382e9ec367acf",
-"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "d617e0f58ca35957441597c78d2ad300358500648de956738784190e698a41b9",
-"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_restart": "0407b02b01cbd0b1f291cc02f25af792cb5dbbbe05306b460bc93fbaa71280a1",
+"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "9fecdb16dff4021aea8355818854ee956a6ebd03f6f7c809a0de4b1220916171",
+"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "8b834e6b8ea4a2bbde85d2e13aad0f49cfc57a4c5a96f36d57aad014c85bf6cc",
+"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_full_completion": "7b1dcfe979bed200c60a5d8fcdd3825ecb7d423e10d555128b4990c74437eeac",
+"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_menu_close": "14f292790e05299e7eae9229b55f350d477316bfc75363e5f84dca94e5852ddd",
+"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "fe2a4e540b890a3367f6f13dcf3d8c511fbce930973c060b2bdaf42358f5329d",
+"T3W1_fr_test_tutorial_eckhart.py::test_tutorial_restart": "b8d657a5b9b701976ddace512190e7621f96170bed8be1ef0ed40d6d20199b44",
"T3W1_pt_test_autolock.py::test_autolock_does_not_interrupt_signing": "185ec5833f9a4f8265dff4840fa82ef95d47c2ad33e335b732018a6bcd36c410",
"T3W1_pt_test_autolock.py::test_autolock_interrupts_passphrase": "a559c9e4a5f11a6b60cba2e22ef2ef20b3cb3cd78d1d08c6d1031f9b4a620dab",
"T3W1_pt_test_autolock.py::test_autolock_interrupts_signing": "c4940d6b2371fb972b3d697edda0f9d08e79375b5bb9f98966ee0c0086cb9bcd",
@@ -28727,12 +28727,12 @@
"T3W1_pt_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "bd8dc8f37d4f4d563df872399aae19b0d6eae42dd0757df8063c884781ab02b6",
"T3W1_pt_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "c4862784fbf511ada670425b26cc0cfde1e3fb8531b11b57613529bb0fcfa7d8",
"T3W1_pt_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "838b784424f810b3eeb036c6a31efdddd8d0a0a08c2cad0c6cda650cc123e971",
-"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "96e311d57c213b5b61fe6f897aed31161a2caee8840b2559bf79e231b993d982",
-"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "ee45b924b9ebaba81f06133d1589afc47de86fd0498277a45b68754a4c533e07",
-"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_full_completion": "fad0db8fffb93949c8ae88feae2767bd17fb534ee6bb16f5d2adb425eea004e2",
-"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_menu_close": "7e8fced6ab5157eeea3c0f8b5897f7db5369a1867c1c433e9dbf137e8ff5749b",
-"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "ff696566c8e5cedb72203549e54f34ce6ee5eef54cf99ee5c1c3aa39a423994a",
-"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_restart": "017ecdbed2f39fe2e9e6cdae9fcbe17e8d2d8acb0cf1d2944ff7a113200e1013"
+"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_cancel_from_confirm_menu": "898ccb9e447515bba396ca6d06f4b3927de58bf1c576daa1f17f24e883e02255",
+"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_cancel_from_main_menu": "30ed4531c186377c0d8cef21b4991be8cd84c6bceb0656e9d1c8ed1ced3f456c",
+"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_full_completion": "8d81950e63623d504c04839487cdb946e328b0b380c7b22f69b969ebfc939bf3",
+"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_menu_close": "67b2e7e80cbd2633ab4b61470412f9a004f97adc18c49da6cbc7a88c4fdd665e",
+"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_menu_tropic": "03406bb3fad9b43c225993766c81427062afe4c375bcb61751e3495a73455710",
+"T3W1_pt_test_tutorial_eckhart.py::test_tutorial_restart": "cb526ad583a13317ca98d6854173e929cf69ae2e4ad81d56875cf4018aa521a0"
},
"device_tests": {
"T3W1_cs_bitcoin-test_authorize_coinjoin.py::test_cancel_authorization": "7cc88d9cc65b0b903d9e87fa088074fb1b7e8e8822e73927d4b09fb143e82002",
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.