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 2244f3cc2d..a2e73c0713 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 @@ -1,9 +1,12 @@ use crate::{ error, + maybe_trace::MaybeTrace, strutil::TString, translations::TR, ui::{ - component::{text::paragraphs::Paragraph, ComponentExt, SwipeDirection}, + component::{ + text::paragraphs::Paragraph, Component, ComponentExt, Paginate, SwipeDirection, + }, flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow, SwipePage}, }, }; @@ -208,3 +211,41 @@ fn new_confirm_action_obj(_args: &[Obj], kwargs: &Map) -> Result( + content: T, + title: TString<'static>, + subtitle: Option>, + verb: Option>, + verb_cancel: Option>, +) -> Result { + let mut frame = Frame::left_aligned(title, SwipePage::vertical(content)) + .with_menu_button() + .with_footer(TR::instructions__swipe_up.into(), verb); + 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()), + ) + } + .with_cancel_button() + .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/flow/mod.rs b/core/embed/rust/src/ui/model_mercury/flow/mod.rs index 0a782b922a..726f695a60 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/mod.rs @@ -10,7 +10,7 @@ pub mod request_number; pub mod show_share_words; pub mod warning_hi_prio; -pub use confirm_action::new_confirm_action; +pub use confirm_action::{new_confirm_action, new_confirm_action_simple}; mod util; pub use confirm_output::new_confirm_output; diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 4a299836b8..85242c04fb 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -449,6 +449,33 @@ impl ConfirmBlobParams { let obj = LayoutObj::new(frame)?; Ok(obj.into()) } + + fn into_flow(self) -> Result { + let paragraphs = ConfirmBlob { + description: self.description.unwrap_or("".into()), + extra: self.extra.unwrap_or("".into()), + data: self.data.try_into()?, + description_font: &theme::TEXT_NORMAL, + extra_font: &theme::TEXT_DEMIBOLD, + data_font: if self.chunkify { + let data: TString = self.data.try_into()?; + theme::get_chunkified_text_style(data.len()) + } else if self.text_mono { + &theme::TEXT_MONO + } else { + &theme::TEXT_NORMAL + }, + } + .into_paragraphs(); + + flow::new_confirm_action_simple( + paragraphs, + self.title, + self.subtitle, + self.verb, + self.verb_cancel, + ) + } } extern "C" fn new_confirm_blob(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { @@ -472,7 +499,7 @@ extern "C" fn new_confirm_blob(n_args: usize, args: *const Obj, kwargs: *mut Map ConfirmBlobParams::new(title, data, description, verb, verb_cancel, hold) .with_extra(extra) .with_chunkify(chunkify) - .into_layout() + .into_flow() }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } @@ -638,7 +665,7 @@ extern "C" fn new_confirm_value(n_args: usize, args: *const Obj, kwargs: *mut Ma .with_info_button(info_button) .with_chunkify(chunkify) .with_text_mono(text_mono) - .into_layout() + .into_flow() }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } @@ -693,10 +720,10 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs: Paragraph::new(&theme::TEXT_MONO, amount_new), ]); - let obj = LayoutObj::new(Frame::left_aligned( - TR::modify_amount__title.into(), - ButtonPage::new(paragraphs, theme::BG) - .with_cancel_confirm(Some("^".into()), Some(TR::buttons__continue.into())), + let obj = LayoutObj::new(SwipeUpScreen::new( + Frame::left_aligned(TR::modify_amount__title.into(), paragraphs) + .with_cancel_button() + .with_footer(TR::instructions__swipe_up.into(), None), ))?; Ok(obj.into()) }; @@ -735,15 +762,11 @@ extern "C" fn new_confirm_modify_fee(n_args: usize, args: *const Obj, kwargs: *m Paragraph::new(&theme::TEXT_MONO, total_fee_new), ]); - let obj = LayoutObj::new( - Frame::left_aligned( - title, - ButtonPage::new(paragraphs, theme::BG) - .with_hold()? - .with_swipe_left(), - ) - .with_menu_button(), - )?; + let obj = LayoutObj::new(SwipeUpScreen::new( + Frame::left_aligned(title, paragraphs) + .with_menu_button() + .with_footer(TR::instructions__swipe_up.into(), None), + ))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -1031,11 +1054,10 @@ extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mu } } - let buttons = Button::cancel_info_confirm(button, info_button); - - let obj = LayoutObj::new(Frame::left_aligned( - title, - Dialog::new(paragraphs.into_paragraphs(), buttons), + let obj = LayoutObj::new(SwipeUpScreen::new( + Frame::left_aligned(title, paragraphs.into_paragraphs()) + .with_menu_button() + .with_footer(TR::instructions__swipe_up.into(), Some(button)), ))?; Ok(obj.into()) }; diff --git a/tests/device_tests/bitcoin/test_signtx.py b/tests/device_tests/bitcoin/test_signtx.py index 68001b2e36..c68608ad75 100644 --- a/tests/device_tests/bitcoin/test_signtx.py +++ b/tests/device_tests/bitcoin/test_signtx.py @@ -1613,6 +1613,7 @@ def test_information_cancel(client: Client): ) +@pytest.mark.skip_t3t1(reason="Not yet implemented in new UI") @pytest.mark.skip_t1b1(reason="Cannot test layouts on T1") def test_information_replacement(client: Client): # Use the change output and an external output to bump the fee. diff --git a/tests/device_tests/cardano/test_sign_tx.py b/tests/device_tests/cardano/test_sign_tx.py index 1842077136..27fd13d883 100644 --- a/tests/device_tests/cardano/test_sign_tx.py +++ b/tests/device_tests/cardano/test_sign_tx.py @@ -62,6 +62,7 @@ def test_cardano_sign_tx(client: Client, parameters, result): assert response == _transform_expected_result(result) +@pytest.mark.skip_t3t1(reason="Not yet implemented in new UI") @parametrize_using_common_fixtures("cardano/sign_tx.show_details.json") def test_cardano_sign_tx_show_details(client: Client, parameters, result): response = call_sign_tx(client, parameters, show_details_input_flow, chunkify=True) diff --git a/tests/device_tests/ethereum/test_sign_typed_data.py b/tests/device_tests/ethereum/test_sign_typed_data.py index 6ce72aa721..60297b9191 100644 --- a/tests/device_tests/ethereum/test_sign_typed_data.py +++ b/tests/device_tests/ethereum/test_sign_typed_data.py @@ -97,6 +97,7 @@ DATA = { } +@pytest.mark.skip_t3t1(reason="Not yet implemented in new UI") @pytest.mark.skip_t1b1 def test_ethereum_sign_typed_data_show_more_button(client: Client): with client: diff --git a/tests/device_tests/ethereum/test_signtx.py b/tests/device_tests/ethereum/test_signtx.py index a14d2d9a6b..752cd37e4b 100644 --- a/tests/device_tests/ethereum/test_signtx.py +++ b/tests/device_tests/ethereum/test_signtx.py @@ -457,6 +457,7 @@ def test_signtx_data_pagination(client: Client, flow): _sign_tx_call() +@pytest.mark.skip_t3t1(reason="Not yet implemented in new UI") @pytest.mark.skip_t1b1("T1 does not support Everstake") @parametrize_using_common_fixtures("ethereum/sign_tx_staking.json") @pytest.mark.parametrize("chunkify", (True, False)) diff --git a/tests/input_flows.py b/tests/input_flows.py index f945dab17d..9e99f74dde 100644 --- a/tests/input_flows.py +++ b/tests/input_flows.py @@ -264,12 +264,12 @@ class InputFlowSignMessagePagination(InputFlowBase): self.debug.press_yes() br = yield - assert br.pages is not None - for i in range(br.pages): + # assert br.pages is not None + for i in range(br.pages or 1): layout = self.debug.wait_layout() layouts.append(layout) - if i < br.pages - 1: + if br.pages and i < br.pages - 1: self.debug.swipe_up() self.message_read = multipage_content(layouts)