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 1ada3437c3..7f32b1bff3 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 @@ -109,6 +109,7 @@ impl FlowController for ConfirmAction { fn handle_swipe(&'static self, direction: Direction) -> Decision { match (self, direction) { (Self::Action, Direction::Up) => self.return_msg(FlowMsg::Confirmed), + (Self::Action, Direction::Down) => self.return_msg(FlowMsg::Back), _ => self.do_nothing(), } } @@ -138,6 +139,7 @@ impl FlowController for ConfirmActionWithConfirmation { fn handle_swipe(&'static self, direction: Direction) -> Decision { match (self, direction) { (Self::Action, Direction::Up) => Self::Confirmation.swipe(direction), + (Self::Action, Direction::Down) => self.return_msg(FlowMsg::Back), (Self::Confirmation, Direction::Down) => Self::Action.swipe(direction), _ => self.do_nothing(), } @@ -170,6 +172,7 @@ impl FlowController for ConfirmActionWithMenu { fn handle_swipe(&'static self, direction: Direction) -> Decision { match (self, direction) { (Self::Action, Direction::Up) => self.return_msg(FlowMsg::Confirmed), + (Self::Action, Direction::Down) => self.return_msg(FlowMsg::Back), _ => self.do_nothing(), } } @@ -202,6 +205,7 @@ impl FlowController for ConfirmActionWithMenuAndConfirmation { fn handle_swipe(&'static self, direction: Direction) -> Decision { match (self, direction) { (Self::Action, Direction::Up) => Self::Confirmation.swipe(direction), + (Self::Action, Direction::Down) => self.return_msg(FlowMsg::Back), (Self::Confirmation, Direction::Down) => Self::Action.swipe(direction), _ => self.do_nothing(), } @@ -264,6 +268,7 @@ pub fn new_confirm_action( }, ConfirmActionStrings::new(title, subtitle, None, prompt_screen.then_some(prompt_title)), hold, + false, None, 0, false, @@ -276,6 +281,7 @@ fn new_confirm_action_uni( extra: ConfirmActionExtra, strings: ConfirmActionStrings, hold: bool, + swipe_down: bool, frame_margin: usize, page_counter: bool, ) -> Result { @@ -286,6 +292,9 @@ fn new_confirm_action_uni( .with_margin(frame_margin) .with_swipeup_footer(strings.footer_description) .with_vertical_pages(); + if swipe_down { + content = content.with_swipe(Direction::Down, SwipeSettings::Default); + } content = match extra { ConfirmActionExtra::ExternalMenu => content.with_menu_button().with_external_menu(), @@ -449,11 +458,13 @@ fn create_confirm( } #[inline(never)] +#[allow(clippy::too_many_arguments)] pub fn new_confirm_action_simple( content: T, extra: ConfirmActionExtra, strings: ConfirmActionStrings, hold: bool, + swipe_down: bool, page_limit: Option, frame_margin: usize, page_counter: bool, @@ -463,6 +474,7 @@ pub fn new_confirm_action_simple extra, strings, hold, + swipe_down, frame_margin, page_counter, ) diff --git a/core/embed/rust/src/ui/layout_delizia/flow/util.rs b/core/embed/rust/src/ui/layout_delizia/flow/util.rs index d8695d950c..053cde96a5 100644 --- a/core/embed/rust/src/ui/layout_delizia/flow/util.rs +++ b/core/embed/rust/src/ui/layout_delizia/flow/util.rs @@ -154,8 +154,8 @@ impl ConfirmValue { self } - pub const fn with_swipe_down(mut self) -> Self { - self.swipe_down = true; + pub const fn with_swipe_down(mut self, swipe_down: bool) -> Self { + self.swipe_down = swipe_down; self } @@ -337,6 +337,7 @@ impl ConfirmValue { ) .with_footer_description(self.footer_description), self.hold, + self.swipe_down, self.page_limit, self.frame_margin, self.page_counter, 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 fea246d872..1da86a3e68 100644 --- a/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs @@ -102,6 +102,7 @@ impl FirmwareUI for UIDelizia { ConfirmActionExtra::ExternalMenu, ConfirmActionStrings::new(title, Some(subtitle), None, None), false, + false, None, 0, false, @@ -123,7 +124,7 @@ impl FirmwareUI for UIDelizia { page_counter: bool, prompt_screen: bool, cancel: bool, - _back_button: bool, + back_button: bool, _warning_footer: Option>, external_menu: bool, ) -> Result { @@ -146,6 +147,7 @@ impl FirmwareUI for UIDelizia { .with_chunkify(chunkify) .with_page_counter(page_counter) .with_cancel(cancel) + .with_swipe_down(back_button) .with_prompt(prompt_screen) .with_external_menu(external_menu) .with_hold(hold) @@ -205,6 +207,7 @@ impl FirmwareUI for UIDelizia { Some(TR::homescreen__settings_title.into()), ), false, + false, None, 0, false, @@ -241,6 +244,7 @@ impl FirmwareUI for UIDelizia { Some(TR::coinjoin__title.into()), ), true, + false, None, 0, false, @@ -270,6 +274,7 @@ impl FirmwareUI for UIDelizia { ConfirmActionExtra::Menu(ConfirmActionMenuStrings::new()), ConfirmActionStrings::new(title, None, None, Some(title)), false, + false, None, 0, false, @@ -338,6 +343,7 @@ impl FirmwareUI for UIDelizia { ), ConfirmActionStrings::new(title, None, None, Some(title)), true, + false, None, 0, false, @@ -460,6 +466,7 @@ impl FirmwareUI for UIDelizia { ConfirmActionExtra::Menu(ConfirmActionMenuStrings::new()), ConfirmActionStrings::new(title, subtitle, None, hold.then_some(title)), hold, + false, None, 0, false, @@ -500,6 +507,7 @@ impl FirmwareUI for UIDelizia { ), ConfirmActionStrings::new(title, None, None, None).with_footer_description(Some(verb)), false, + false, None, 0, false, diff --git a/core/src/trezor/ui/layouts/delizia/__init__.py b/core/src/trezor/ui/layouts/delizia/__init__.py index 214caf2f36..b934ef2846 100644 --- a/core/src/trezor/ui/layouts/delizia/__init__.py +++ b/core/src/trezor/ui/layouts/delizia/__init__.py @@ -25,6 +25,7 @@ BR_CODE_OTHER = ButtonRequestType.Other # global_import_cache CONFIRMED = trezorui_api.CONFIRMED CANCELLED = trezorui_api.CANCELLED INFO = trezorui_api.INFO +BACK = trezorui_api.BACK def confirm_action( @@ -614,28 +615,33 @@ async def confirm_output( ] else: info_items = [] - - await confirm_value( - TR.words__address, - address, - description or "", - "confirm_output", - br_code, - subtitle=title, - chunkify=chunkify, - cancel_text=TR.send__cancel_sign, - info_items=info_items, - ) - await confirm_value( - TR.words__amount, - amount, - "", - "confirm_output", - br_code, - subtitle=title, - cancel_text=TR.send__cancel_sign, - info_items=info_items, - ) + while True: + await confirm_value( + TR.words__address, + address, + description or "", + "confirm_output", + br_code, + subtitle=title, + chunkify=chunkify, + cancel_text=TR.send__cancel_sign, + info_items=info_items, + ) + amount_response = await confirm_value( + TR.words__amount, + amount, + description="", + br_name="confirm_output", + br_code=br_code, + subtitle=title, + cancel_text=TR.send__cancel_sign, + info_items=info_items, + can_go_back=True, + ) + if amount_response is BACK: + continue + else: + break else: await raise_if_not_confirmed( trezorui_api.flow_confirm_output( @@ -834,6 +840,7 @@ def confirm_value( verb: str | None = None, subtitle: str | None = None, hold: bool = False, + can_go_back: bool = False, is_data: bool = True, chunkify: bool = False, info_items: ( @@ -856,6 +863,7 @@ def confirm_value( hold=hold, chunkify=chunkify, cancel=cancel, + back_button=can_go_back, external_menu=True, ) diff --git a/core/src/trezor/ui/layouts/eckhart/__init__.py b/core/src/trezor/ui/layouts/eckhart/__init__.py index 1b665d1d10..5d3cd53d9c 100644 --- a/core/src/trezor/ui/layouts/eckhart/__init__.py +++ b/core/src/trezor/ui/layouts/eckhart/__init__.py @@ -636,10 +636,10 @@ async def confirm_output( external_menu=True, back_button=True, ) - if ( - await interact_with_menu(amount_layout, menu, "confirm_output", br_code) - is BACK - ): + amount_response = await interact_with_menu( + amount_layout, menu, "confirm_output", br_code + ) + if amount_response is BACK: continue else: break diff --git a/tests/device_tests/bitcoin/test_signtx.py b/tests/device_tests/bitcoin/test_signtx.py index 0d7a5e970a..ec3c4570a9 100644 --- a/tests/device_tests/bitcoin/test_signtx.py +++ b/tests/device_tests/bitcoin/test_signtx.py @@ -158,7 +158,7 @@ def test_one_one_fee(session: Session): ) -@pytest.mark.models("t3w1") +@pytest.mark.models("t3w1", "t3t1") def test_one_one_fee_back_from_amount(session: Session): # input tx: 0dac366fd8a67b2a89fbb0d31086e7acded7a5bbf9ef9daa935bc873229ef5b5 diff --git a/tests/input_flows.py b/tests/input_flows.py index 43fc94d095..3f2bb88052 100644 --- a/tests/input_flows.py +++ b/tests/input_flows.py @@ -1208,17 +1208,50 @@ class InputFlowSignTxBackFromAmount(InputFlowBase): def __init__(self, client: Client): super().__init__(client) - def input_flow_eckhart(self) -> BRGeneratorType: - yield # confirm address - self.debug.read_layout() - self.debug.click(self.debug.screen_buttons.ok()) + def input_flow_delizia(self) -> BRGeneratorType: + yield + layout = self.debug.read_layout() + assert TR.words__address in layout.title() + assert TR.words__recipient + " #1" in layout.title() + self.debug.swipe_up() - yield # confirm amount - self.debug.read_layout() - self.debug.click(self.debug.screen_buttons.cancel()) + yield + layout = self.debug.read_layout() + assert TR.words__amount in layout.title() + assert TR.words__recipient + " #1" in layout.title() + self.debug.swipe_down() + + yield + layout = self.debug.read_layout() + assert TR.words__address in layout.title() + assert TR.words__recipient + " #1" in layout.title() + self.debug.swipe_up() yield self.debug.read_layout() + self.debug.swipe_up() + + yield + self.debug.read_layout() + self.debug.press_yes() + + def input_flow_eckhart(self) -> BRGeneratorType: + yield + layout = self.debug.read_layout() + assert TR.words__send in layout.title() + assert TR.words__recipient + " #1" in layout.title() + self.debug.click(self.debug.screen_buttons.ok()) + + yield + layout = self.debug.read_layout() + assert TR.words__amount in layout.text_content() + assert TR.words__recipient + " #1" in layout.title() + self.debug.click(self.debug.screen_buttons.cancel()) + + yield + layout = self.debug.read_layout() + assert TR.words__send in layout.title() + assert TR.words__recipient + " #1" in layout.title() self.debug.click(self.debug.screen_buttons.ok()) yield