diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 99bc9e2056..5fc2d0da5b 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -398,6 +398,7 @@ static void _librust_qstrs(void) { MP_QSTR_progress_event; MP_QSTR_prompt; MP_QSTR_prompt_screen; + MP_QSTR_prompt_title; MP_QSTR_qr_title; MP_QSTR_reboot_to_bootloader__just_a_moment; MP_QSTR_reboot_to_bootloader__restart; diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs index b9d63ee911..394dff2b23 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs @@ -141,6 +141,7 @@ fn new_confirm_action_obj(_args: &[Obj], kwargs: &Map) -> Result Result( + content: T, + title: TString<'static>, + subtitle: Option>, + verb_cancel: Option>, + prompt_screen: Option>, + hold: bool, +) -> Result { let mut content_intro = - Frame::left_aligned(title, SwipeContent::new(SwipePage::vertical(paragraphs))) + Frame::left_aligned(title, SwipeContent::new(SwipePage::vertical(content))) .with_menu_button() .with_footer(TR::instructions__swipe_up.into(), None) .with_swipe(SwipeDirection::Up, SwipeSettings::default()) @@ -170,10 +190,13 @@ fn new_confirm_action_obj(_args: &[Obj], kwargs: &Map) -> Result Some(FlowMsg::Info), - _ => None, - }); + let prompt_pages: usize = prompt_screen.is_some().into(); + let content_intro = content_intro + .map(move |msg| match msg { + FrameMsg::Button(_) => Some(FlowMsg::Info), + _ => None, + }) + .with_pages(move |intro_pages| intro_pages + prompt_pages); let content_menu = if let Some(verb_cancel) = verb_cancel { Frame::left_aligned( @@ -193,11 +216,7 @@ fn new_confirm_action_obj(_args: &[Obj], kwargs: &Map) -> Result Some(FlowMsg::Cancelled), }); - if !prompt_screen && !hold { - let store = flow_store().add(content_intro)?.add(content_menu)?; - let res = SwipeFlow::new(ConfirmActionSimple::Intro, store)?; - Ok(LayoutObj::new(res)?.into()) - } else { + if let Some(prompt_title) = prompt_screen { let (prompt, prompt_action) = if hold { ( PromptScreen::new_hold_to_confirm(), @@ -210,9 +229,7 @@ fn new_confirm_action_obj(_args: &[Obj], kwargs: &Map) -> Result Result( - content: T, - title: TString<'static>, - subtitle: Option>, - verb: Option>, - verb_cancel: Option>, -) -> Result { - let mut frame = Frame::left_aligned(title, SwipeContent::new(SwipePage::vertical(content))) - .with_menu_button() - .with_footer(TR::instructions__swipe_up.into(), verb) - .with_swipe(SwipeDirection::Up, SwipeSettings::default()) - .with_swipe(SwipeDirection::Left, SwipeSettings::immediate()) - .with_vertical_pages(); - if let Some(subtitle) = subtitle { - frame = frame.with_subtitle(subtitle) - } - let content_intro = - frame.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info)); - - let content_menu = if let Some(verb_cancel) = verb_cancel { - Frame::left_aligned( - "".into(), - VerticalMenu::empty().danger(theme::ICON_CANCEL, verb_cancel), - ) } else { - Frame::left_aligned( - "".into(), - VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()), - ) + let store = flow_store().add(content_intro)?.add(content_menu)?; + let res = SwipeFlow::new(ConfirmActionSimple::Intro, store)?; + Ok(LayoutObj::new(res)?.into()) } - .with_cancel_button() - .with_swipe(SwipeDirection::Right, SwipeSettings::immediate()) - .map(move |msg| match msg { - FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)), - FrameMsg::Button(_) => Some(FlowMsg::Cancelled), - }); - - let store = flow_store().add(content_intro)?.add(content_menu)?; - let res = SwipeFlow::new(ConfirmActionSimple::Intro, store)?; - Ok(LayoutObj::new(res)?.into()) } diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 66329789e9..1656dfb83a 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -271,10 +271,6 @@ impl ComponentMsgObj for super::component::bl_confirm::Confirm<'_> { extern "C" fn new_confirm_emphasized(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 verb: Option = kwargs - .get(Qstr::MP_QSTR_verb) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; let mut ops = OpTextLayout::new(theme::TEXT_NORMAL); @@ -296,8 +292,9 @@ extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *m FormattedText::new(ops).vertically_centered(), title, None, - verb, None, + Some(title), + false, ) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -312,6 +309,7 @@ struct ConfirmBlobParams { verb: Option>, verb_cancel: Option>, info_button: bool, + prompt: bool, hold: bool, chunkify: bool, text_mono: bool, @@ -324,6 +322,7 @@ impl ConfirmBlobParams { description: Option>, verb: Option>, verb_cancel: Option>, + prompt: bool, hold: bool, ) -> Self { Self { @@ -335,6 +334,7 @@ impl ConfirmBlobParams { verb, verb_cancel, info_button: false, + prompt, hold, chunkify: false, text_mono: true, @@ -388,8 +388,9 @@ impl ConfirmBlobParams { paragraphs, self.title, self.subtitle, - self.verb, self.verb_cancel, + self.prompt.then_some(self.title), + self.hold, ) } } @@ -414,11 +415,20 @@ extern "C" fn new_confirm_blob(n_args: usize, args: *const Obj, kwargs: *mut Map .try_into_option()?; let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; + let prompt_screen: bool = kwargs.get_or(Qstr::MP_QSTR_prompt_screen, true)?; - ConfirmBlobParams::new(title, data, description, verb, verb_cancel, hold) - .with_extra(extra) - .with_chunkify(chunkify) - .into_flow() + ConfirmBlobParams::new( + title, + data, + description, + verb, + verb_cancel, + prompt_screen, + hold, + ) + .with_extra(extra) + .with_chunkify(chunkify) + .into_flow() }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } @@ -449,7 +459,7 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut } .into_paragraphs(); - flow::new_confirm_action_simple(paragraphs, title, None, None, None) + flow::new_confirm_action_simple(paragraphs, title, None, None, None, false) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } @@ -457,7 +467,7 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut extern "C" fn new_confirm_properties(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 _hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; // FIXME + let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; let paragraphs = PropsList::new( @@ -471,8 +481,9 @@ extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *m paragraphs.into_paragraphs(), title, None, - Some(TR::buttons__confirm.into()), None, + hold.then_some(title), + hold, ) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -579,7 +590,7 @@ extern "C" fn new_confirm_value(n_args: usize, args: *const Obj, kwargs: *mut Ma let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; let text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; - ConfirmBlobParams::new(title, value, description, verb, verb_cancel, hold) + ConfirmBlobParams::new(title, value, description, verb, verb_cancel, hold, hold) .with_subtitle(subtitle) .with_info_button(info_button) .with_chunkify(chunkify) @@ -900,8 +911,14 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut Paragraph::new(&theme::TEXT_MONO, max_feerate), ]); - // FIXME: hold - flow::new_confirm_action_simple(paragraphs, TR::coinjoin__title.into(), None, None, None) + flow::new_confirm_action_simple( + paragraphs, + TR::coinjoin__title.into(), + None, + None, + Some(TR::coinjoin__title.into()), + true, + ) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } @@ -1367,6 +1384,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// hold_danger: bool = False, /// reverse: bool = False, /// prompt_screen: bool = False, + /// prompt_title: str | None = None, /// ) -> LayoutObj[UiResult]: /// """Confirm action.""" Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, flow::confirm_action::new_confirm_action).as_obj(), @@ -1399,6 +1417,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// verb_cancel: str | None = None, /// hold: bool = False, /// chunkify: bool = False, + /// prompt_screen: bool = False, /// ) -> LayoutObj[UiResult]: /// """Confirm byte sequence data.""" Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(), diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index b694452e83..8f4033ffcf 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -1652,6 +1652,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// hold_danger: bool = False, # unused on TR /// reverse: bool = False, /// prompt_screen: bool = False, + /// prompt_title: str | None = None, /// ) -> LayoutObj[UiResult]: /// """Confirm action.""" Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(), @@ -1674,6 +1675,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// verb_cancel: str | None = None, /// hold: bool = False, /// chunkify: bool = False, + /// prompt_screen: bool = False, /// ) -> LayoutObj[UiResult]: /// """Confirm byte sequence data.""" Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(), diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 873b016c8f..8e638bb3d3 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -1721,6 +1721,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// hold_danger: bool = False, /// reverse: bool = False, /// prompt_screen: bool = False, + /// prompt_title: str | None = None, /// ) -> LayoutObj[UiResult]: /// """Confirm action.""" Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(), @@ -1753,6 +1754,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// verb_cancel: str | None = None, /// hold: bool = False, /// chunkify: bool = False, + /// prompt_screen: bool = False, /// ) -> LayoutObj[UiResult]: /// """Confirm byte sequence data.""" Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(), diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index f58b64cce9..e680d2a87a 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -85,6 +85,7 @@ def confirm_action( hold_danger: bool = False, reverse: bool = False, prompt_screen: bool = False, + prompt_title: str | None = None, ) -> LayoutObj[UiResult]: """Confirm action.""" @@ -120,6 +121,7 @@ def confirm_blob( verb_cancel: str | None = None, hold: bool = False, chunkify: bool = False, + prompt_screen: bool = False, ) -> LayoutObj[UiResult]: """Confirm byte sequence data.""" @@ -632,6 +634,7 @@ def confirm_action( hold_danger: bool = False, # unused on TR reverse: bool = False, prompt_screen: bool = False, + prompt_title: str | None = None, ) -> LayoutObj[UiResult]: """Confirm action.""" @@ -656,6 +659,7 @@ def confirm_blob( verb_cancel: str | None = None, hold: bool = False, chunkify: bool = False, + prompt_screen: bool = False, ) -> LayoutObj[UiResult]: """Confirm byte sequence data.""" @@ -1160,6 +1164,7 @@ def confirm_action( hold_danger: bool = False, reverse: bool = False, prompt_screen: bool = False, + prompt_title: str | None = None, ) -> LayoutObj[UiResult]: """Confirm action.""" @@ -1195,6 +1200,7 @@ def confirm_blob( verb_cancel: str | None = None, hold: bool = False, chunkify: bool = False, + prompt_screen: bool = False, ) -> LayoutObj[UiResult]: """Confirm byte sequence data.""" diff --git a/core/src/apps/common/passphrase.py b/core/src/apps/common/passphrase.py index b09ed92c03..0d57cd1785 100644 --- a/core/src/apps/common/passphrase.py +++ b/core/src/apps/common/passphrase.py @@ -63,6 +63,8 @@ async def _request_on_host() -> str: "passphrase_host1_hidden", TR.passphrase__hidden_wallet, description=TR.passphrase__from_host_not_shown, + prompt_screen=True, + prompt_title=TR.passphrase__access_hidden_wallet, ) else: await confirm_action( diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index 4036cbf907..ad8f5c6c8f 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -296,6 +296,7 @@ async def confirm_action( exc: ExceptionType = ActionCancelled, br_code: ButtonRequestType = BR_TYPE_OTHER, prompt_screen: bool = False, + prompt_title: str | None = None, ) -> None: if description is not None and description_param is not None: description = description.format(description_param) @@ -314,6 +315,7 @@ async def confirm_action( hold_danger=hold_danger, reverse=reverse, prompt_screen=prompt_screen, + prompt_title=prompt_title or title, ) ), br_type, @@ -727,6 +729,7 @@ async def confirm_blob( br_code: ButtonRequestType = BR_TYPE_OTHER, ask_pagination: bool = False, chunkify: bool = False, + prompt_screen: bool = True, ) -> None: layout = RustLayout( trezorui2.confirm_blob( @@ -738,6 +741,7 @@ async def confirm_blob( verb=verb, verb_cancel=verb_cancel, chunkify=chunkify, + prompt_screen=prompt_screen, ) ) @@ -987,6 +991,7 @@ if not utils.BITCOIN_ONLY: recipient, verb=TR.buttons__continue, chunkify=chunkify, + prompt_screen=False, ) try: diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 8e72314d99..edebfa046e 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -387,6 +387,7 @@ def confirm_action( exc: ExceptionType = ActionCancelled, br_code: ButtonRequestType = BR_TYPE_OTHER, prompt_screen: bool = False, + prompt_title: str | None = None, ) -> Awaitable[None]: verb = verb or TR.buttons__confirm # def_arg if description is not None and description_param is not None: @@ -860,6 +861,7 @@ def confirm_blob( br_code: ButtonRequestType = BR_TYPE_OTHER, ask_pagination: bool = False, chunkify: bool = False, + prompt_screen: bool = True, ) -> Awaitable[None]: verb = verb or TR.buttons__confirm # def_arg layout = RustLayout( diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 6d15501d54..48fef1b043 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -302,6 +302,7 @@ def confirm_action( exc: ExceptionType = ActionCancelled, br_code: ButtonRequestType = BR_TYPE_OTHER, prompt_screen: bool = False, + prompt_title: str | None = None, ) -> Awaitable[None]: if description is not None and description_param is not None: description = description.format(description_param) @@ -825,6 +826,7 @@ def confirm_blob( br_code: ButtonRequestType = BR_TYPE_OTHER, ask_pagination: bool = False, chunkify: bool = False, + prompt_screen: bool = True, ) -> Awaitable[None]: verb = verb or TR.buttons__confirm # def_arg layout = RustLayout(