diff --git a/core/embed/rust/src/ui/api/firmware_micropython.rs b/core/embed/rust/src/ui/api/firmware_micropython.rs index 97ddf23404..08a6641fee 100644 --- a/core/embed/rust/src/ui/api/firmware_micropython.rs +++ b/core/embed/rust/src/ui/api/firmware_micropython.rs @@ -951,8 +951,9 @@ extern "C" fn new_show_progress(n_args: usize, args: *const Obj, kwargs: *mut Ma .get(Qstr::MP_QSTR_title) .and_then(Obj::try_into_option) .unwrap_or(None); + let danger: bool = kwargs.get_or(Qstr::MP_QSTR_danger, false)?; - let layout = ModelUI::show_progress(description, indeterminate, title)?; + let layout = ModelUI::show_progress(description, indeterminate, title, danger)?; Ok(LayoutObj::new_root(layout)?.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -1739,6 +1740,7 @@ pub static mp_module_trezorui_api: Module = obj_module! { /// description: str, /// indeterminate: bool = False, /// title: str | None = None, + /// danger: bool = False, /// ) -> LayoutObj[UiResult]: /// """Show progress loader. Please note that the number of lines reserved on screen for /// description is determined at construction time. If you want multiline descriptions diff --git a/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs b/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs index 31089545e6..b4f95bf44d 100644 --- a/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs @@ -1031,6 +1031,7 @@ impl FirmwareUI for UIBolt { description: TString<'static>, indeterminate: bool, title: Option>, + _danger: bool, ) -> Result { let (title, description) = if let Some(title) = title { (title, description) diff --git a/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs b/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs index 738436e259..4d5ed3c1e4 100644 --- a/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs @@ -1166,6 +1166,7 @@ impl FirmwareUI for UICaesar { description: TString<'static>, indeterminate: bool, title: Option>, + _danger: bool, ) -> Result { let mut progress = Progress::new(indeterminate, description); if let Some(title) = title { diff --git a/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs b/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs index 3fecd225e7..696abf840f 100644 --- a/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs @@ -1003,6 +1003,7 @@ impl FirmwareUI for UIDelizia { description: TString<'static>, indeterminate: bool, title: Option>, + _danger: bool, ) -> Result { let (title, description) = if let Some(title) = title { (title, description) diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/progress_screen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/progress_screen.rs index ed5ee17cf3..5ced9a9099 100644 --- a/core/embed/rust/src/ui/layout_eckhart/firmware/progress_screen.rs +++ b/core/embed/rust/src/ui/layout_eckhart/firmware/progress_screen.rs @@ -38,12 +38,17 @@ impl ProgressScreen { title: TString<'static>, indeterminate: bool, description: TString<'static>, + danger: bool, ) -> Self { Self { indeterminate, text: Self::create_paragraphs(title, description), value: 0, - border: ScreenBorder::new(theme::GREEN_LIME), + border: ScreenBorder::new(if danger { + theme::ORANGE + } else { + theme::GREEN_LIME + }), coinjoin_progress: false, coinjoin_do_not_disconnect: None, } diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs index 7fe254f091..5f8bddcf4e 100644 --- a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs @@ -1191,6 +1191,7 @@ impl FirmwareUI for UIEckhart { description: TString<'static>, indeterminate: bool, title: Option>, + danger: bool, ) -> Result { let (title, description) = if let Some(title) = title { (title, description) @@ -1202,6 +1203,7 @@ impl FirmwareUI for UIEckhart { title, indeterminate, description, + danger, )); Ok(layout) } diff --git a/core/embed/rust/src/ui/ui_firmware.rs b/core/embed/rust/src/ui/ui_firmware.rs index 29c2b98d56..4f18b22df5 100644 --- a/core/embed/rust/src/ui/ui_firmware.rs +++ b/core/embed/rust/src/ui/ui_firmware.rs @@ -358,6 +358,7 @@ pub trait FirmwareUI { description: TString<'static>, indeterminate: bool, title: Option>, + danger: bool, ) -> Result; fn show_progress_coinjoin( diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi index 7e2406ad94..387b0f5d46 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -626,6 +626,7 @@ def show_progress( description: str, indeterminate: bool = False, title: str | None = None, + danger: bool = False, ) -> LayoutObj[UiResult]: """Show progress loader. Please note that the number of lines reserved on screen for description is determined at construction time. If you want multiline descriptions diff --git a/core/src/apps/management/wipe_device.py b/core/src/apps/management/wipe_device.py index b6e60057a6..75bcbcb6c7 100644 --- a/core/src/apps/management/wipe_device.py +++ b/core/src/apps/management/wipe_device.py @@ -27,7 +27,7 @@ async def wipe_device(msg: WipeDevice) -> Success: ) # start an empty progress screen so that the screen is not blank while waiting - render_empty_loader(config.StorageMessage.PROCESSING_MSG) + render_empty_loader(config.StorageMessage.PROCESSING_MSG, danger=True) # wipe storage storage.wipe() diff --git a/core/src/trezor/pin.py b/core/src/trezor/pin.py index 4880b5fd52..8a04d7db75 100644 --- a/core/src/trezor/pin.py +++ b/core/src/trezor/pin.py @@ -26,14 +26,22 @@ def allow_all_loader_messages() -> None: _ignore_loader_messages = False -def render_empty_loader(message: config.StorageMessage, description: str = "") -> None: - """Render empty loader to prevent the screen appear to be frozen.""" +def render_empty_loader( + message: config.StorageMessage, description: str = "", danger: bool = False +) -> None: + """Render empty loader to prevent the screen from appearing frozen. + + Args: + message (config.StorageMessage): The message to display in the loader. + description (str, optional): Additional description to display. Defaults to an empty string. + danger (bool, optional): If True, renders the loader in a 'danger' style to indicate a critical operation (e.g. wipe device). Defaults to False. + """ from trezor.ui.layouts.progress import pin_progress global _progress_layout global _started_with_empty_loader - _progress_layout = pin_progress(message, description) + _progress_layout = pin_progress(message, description, danger) _progress_layout.report(0, None) _started_with_empty_loader = True diff --git a/core/src/trezor/ui/layouts/progress.py b/core/src/trezor/ui/layouts/progress.py index da67b4f9a0..5269f6d10b 100644 --- a/core/src/trezor/ui/layouts/progress.py +++ b/core/src/trezor/ui/layouts/progress.py @@ -25,7 +25,19 @@ def progress( description: str | None = None, title: str | None = None, indeterminate: bool = False, + danger: bool = False, ) -> ui.ProgressLayout: + """ + Displays a progress layout with optional description and title. + + Args: + description (str | None): The description text to display. Defaults to a generic "please wait" message. + title (str | None): The title text to display. Defaults to None. + indeterminate (bool): Whether the progress is indeterminate (e.g., a spinner). Defaults to False. + danger (bool): Whether to apply the "danger" style to indicate a critical operation, e.g. wipe device. Defaults to False. + Returns: + ui.ProgressLayout: The configured progress layout. + """ if description is None: description = TR.progress__please_wait # def_arg @@ -34,6 +46,7 @@ def progress( description=description, title=title, indeterminate=indeterminate, + danger=danger, ) ) @@ -48,8 +61,12 @@ def coinjoin_progress(message: str) -> ui.ProgressLayout: ) -def pin_progress(title: config.StorageMessage, description: str) -> ui.ProgressLayout: - return progress(description=description, title=_storage_message_to_str(title)) +def pin_progress( + title: config.StorageMessage, description: str, danger: bool = False +) -> ui.ProgressLayout: + return progress( + description=description, title=_storage_message_to_str(title), danger=danger + ) if not utils.BITCOIN_ONLY: