diff --git a/core/embed/rust/src/ui/flow/page.rs b/core/embed/rust/src/ui/flow/page.rs index 06b8ba437f..e34ce9196a 100644 --- a/core/embed/rust/src/ui/flow/page.rs +++ b/core/embed/rust/src/ui/flow/page.rs @@ -45,6 +45,17 @@ impl SwipePage { } } + pub fn horizontal(inner: T) -> Self { + Self { + inner, + bounds: Rect::zero(), + axis: Axis::Horizontal, + pages: 1, + current: 0, + transition: None, + } + } + fn handle_transition(ctx: &mut EventCtx, event: Event, transition: &mut Transition) -> bool { let mut finished = false; if let Event::Timer(EventCtx::ANIM_FRAME_TIMER) = event { diff --git a/core/embed/rust/src/ui/model_mercury/component/address_details.rs b/core/embed/rust/src/ui/model_mercury/component/address_details.rs index 0ecb87a4e2..79cde1c1f1 100644 --- a/core/embed/rust/src/ui/model_mercury/component/address_details.rs +++ b/core/embed/rust/src/ui/model_mercury/component/address_details.rs @@ -56,14 +56,12 @@ impl AddressDetails { } let result = Self { details: Frame::left_aligned(details_title, para.into_paragraphs()) - .with_cancel_button() - .with_border(theme::borders_horizontal_scroll()), + .with_cancel_button(), xpub_view: Frame::left_aligned( " \n ".into(), Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, "").into_paragraphs(), ) - .with_cancel_button() - .with_border(theme::borders_horizontal_scroll()), + .with_cancel_button(), xpubs: Vec::new(), xpub_page_count: Vec::new(), current_page: 0, diff --git a/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs b/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs index d9c61466d0..1f9a99be3f 100644 --- a/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs +++ b/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs @@ -139,7 +139,7 @@ impl crate::ui::flow::Swipable for PromptScreen {} #[cfg(feature = "ui_debug")] impl crate::trace::Trace for PromptScreen { fn trace(&self, t: &mut dyn crate::trace::Tracer) { - t.component("StatusScreen"); + t.component("PromptScreen"); t.child("button", &self.button); } } diff --git a/core/embed/rust/src/ui/model_mercury/flow/get_address.rs b/core/embed/rust/src/ui/model_mercury/flow/get_address.rs index 8fc055cbbe..d598cd378a 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/get_address.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/get_address.rs @@ -222,7 +222,7 @@ impl GetAddress { let [xtitle, text]: [TString; 2] = util::iter_into_array(i)?; ad.add_xpub(xtitle, text)?; } - let content_account = SwipePage::vertical(ad).map(|_| Some(FlowMsg::Cancelled)); + let content_account = SwipePage::horizontal(ad).map(|_| Some(FlowMsg::Cancelled)); // Cancel let content_cancel_info = Frame::left_aligned( diff --git a/tests/buttons.py b/tests/buttons.py index 40a5ee6958..84f71fac7d 100644 --- a/tests/buttons.py +++ b/tests/buttons.py @@ -40,6 +40,14 @@ RESET_WORD_CHECK = [ (MID, grid(DISPLAY_HEIGHT, 5, 4)), ] +VERTICAL_MENU = [ + (MID, grid(DISPLAY_HEIGHT, 4, 1)), + (MID, grid(DISPLAY_HEIGHT, 4, 2)), + (MID, grid(DISPLAY_HEIGHT, 4, 3)), +] + +TAP_TO_CONFIRM = VERTICAL_MENU[1] + BUTTON_LETTERS_BIP39 = ("abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz") BUTTON_LETTERS_SLIP39 = ("ab", "cd", "ef", "ghij", "klm", "nopq", "rs", "tuv", "wxyz") diff --git a/tests/input_flows.py b/tests/input_flows.py index d683d25223..c3abebdf82 100644 --- a/tests/input_flows.py +++ b/tests/input_flows.py @@ -358,15 +358,30 @@ class InputFlowShowAddressQRCode(InputFlowBase): yield self.debug.click(buttons.CORNER_BUTTON, wait=True) # synchronize; TODO get rid of this once we have single-global-layout - self.debug.synchronize_at("SimplePage") - - self.debug.swipe_left(wait=True) - self.debug.swipe_right(wait=True) - self.debug.swipe_left(wait=True) + self.debug.synchronize_at("VerticalMenu") + # menu + self.debug.click(buttons.VERTICAL_MENU[0], wait=True) + self.debug.synchronize_at("Qr") + # qr code self.debug.click(buttons.CORNER_BUTTON, wait=True) - self.debug.press_no(wait=True) - self.debug.press_no(wait=True) - self.debug.press_yes() + # menu + self.debug.click(buttons.VERTICAL_MENU[1], wait=True) + # address details + self.debug.click(buttons.CORNER_BUTTON, wait=True) + # menu + self.debug.click(buttons.VERTICAL_MENU[2], wait=True) + # cancel + self.debug.swipe_up(wait=True) + # really cancel + self.debug.click(buttons.CORNER_BUTTON, wait=True) + # menu + layout = self.debug.click(buttons.CORNER_BUTTON, wait=True) + + while "PromptScreen" not in layout.all_components(): + layout = self.debug.swipe_up(wait=True) + self.debug.synchronize_at("PromptScreen") + # tap to confirm + self.debug.click(buttons.TAP_TO_CONFIRM) class InputFlowShowAddressQRCodeCancel(InputFlowBase): @@ -403,12 +418,23 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase): yield self.debug.click(buttons.CORNER_BUTTON, wait=True) # synchronize; TODO get rid of this once we have single-global-layout - self.debug.synchronize_at("SimplePage") - - self.debug.swipe_left(wait=True) + self.debug.synchronize_at("VerticalMenu") + # menu + self.debug.click(buttons.VERTICAL_MENU[0], wait=True) + self.debug.synchronize_at("Qr") + # qr code self.debug.click(buttons.CORNER_BUTTON, wait=True) - self.debug.press_no(wait=True) - self.debug.press_yes() + # menu + self.debug.click(buttons.VERTICAL_MENU[1], wait=True) + # address details + self.debug.click(buttons.CORNER_BUTTON, wait=True) + # menu + self.debug.click(buttons.VERTICAL_MENU[2], wait=True) + # cancel + self.debug.swipe_up(wait=True) + self.debug.synchronize_at("PromptScreen") + # really cancel + self.debug.click(buttons.TAP_TO_CONFIRM, wait=True) class InputFlowShowMultisigXPUBs(InputFlowBase): @@ -494,36 +520,53 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): def input_flow_t3t1(self) -> BRGeneratorType: yield # multisig address warning - self.debug.press_yes() + self.debug.click(buttons.CORNER_BUTTON, wait=True) + self.debug.synchronize_at("VerticalMenu") + self.debug.click(buttons.VERTICAL_MENU[1]) yield # show address layout = self.debug.wait_layout() TR.assert_in(layout.title(), "address__title_receive_address") - assert "(MULTISIG)" in layout.title() assert layout.text_content().replace(" ", "") == self.address - self.debug.click(buttons.CORNER_BUTTON) + self.debug.click(buttons.CORNER_BUTTON, wait=True) + assert "VerticalMenu" in self.all_components() + # menu + self.debug.click(buttons.VERTICAL_MENU[0], wait=True) + self.debug.synchronize_at("Qr") + # qr code assert "Qr" in self.all_components() - - layout = self.debug.swipe_left(wait=True) + self.debug.click(buttons.CORNER_BUTTON, wait=True) + # menu + assert "VerticalMenu" in self.all_components() + self.debug.click(buttons.VERTICAL_MENU[1], wait=True) + layout = self.debug.synchronize_at("AddressDetails") # address details assert "Multisig 2 of 3" in layout.screen_content() - TR.assert_in(layout.screen_content(), "address_details__derivation_path_colon") + TR.assert_in(layout.screen_content(), "address_details__derivation_path") - # Three xpub pages with the same testing logic - for xpub_num in range(3): - expected_title = f"MULTISIG XPUB #{xpub_num + 1}" + # three xpub pages with the same testing logic + for _xpub_num in range(3): + layout = self.debug.swipe_left(wait=True) layout = self.debug.swipe_left(wait=True) - assert expected_title in layout.title() - content = layout.text_content().replace(" ", "") - assert self.xpubs[xpub_num] in content self.debug.click(buttons.CORNER_BUTTON, wait=True) - # show address - self.debug.press_no(wait=True) - # address mismatch - self.debug.press_no(wait=True) - # show address + layout = self.debug.synchronize_at("VerticalMenu") + # menu + self.debug.click(buttons.VERTICAL_MENU[2], wait=True) + # cancel + self.debug.swipe_up(wait=True) + # really cancel + self.debug.click(buttons.CORNER_BUTTON, wait=True) + layout = self.debug.synchronize_at("VerticalMenu") + # menu + self.debug.click(buttons.CORNER_BUTTON, wait=True) + layout = self.debug.synchronize_at("Paragraphs") + # address + while "PromptScreen" not in layout.all_components(): + layout = self.debug.swipe_up(wait=True) + self.debug.synchronize_at("PromptScreen") + # tap to confirm self.debug.press_yes() @@ -598,19 +641,42 @@ class InputFlowShowXpubQRCode(InputFlowBase): if "coinjoin" in layout.title().lower() or br.code == B.UnknownDerivationPath: self.debug.press_yes() br = yield + layout = self.debug.wait_layout() + + TR.assert_in(layout.title(), "address__title_receive_address") self.debug.click(buttons.CORNER_BUTTON, wait=True) - # synchronize; TODO get rid of this once we have single-global-layout - self.debug.synchronize_at("SimplePage") - - self.debug.swipe_left(wait=True) - self.debug.swipe_right(wait=True) - self.debug.swipe_left(wait=True) + assert "VerticalMenu" in self.all_components() + # menu + self.debug.click(buttons.VERTICAL_MENU[0], wait=True) + self.debug.synchronize_at("Qr") + # qr code + assert "Qr" in self.all_components() self.debug.click(buttons.CORNER_BUTTON, wait=True) - self.debug.press_no(wait=True) - self.debug.press_no(wait=True) - for _ in range(br.pages - 1): - self.debug.swipe_up(wait=True) + # menu + assert "VerticalMenu" in self.all_components() + self.debug.click(buttons.VERTICAL_MENU[1], wait=True) + layout = self.debug.synchronize_at("AddressDetails") + # address details + TR.assert_in(layout.screen_content(), "address_details__derivation_path") + + self.debug.click(buttons.CORNER_BUTTON, wait=True) + layout = self.debug.synchronize_at("VerticalMenu") + # menu + self.debug.click(buttons.VERTICAL_MENU[2], wait=True) + # cancel + self.debug.swipe_up(wait=True) + # really cancel + self.debug.click(buttons.CORNER_BUTTON, wait=True) + layout = self.debug.synchronize_at("VerticalMenu") + # menu + self.debug.click(buttons.CORNER_BUTTON, wait=True) + layout = self.debug.synchronize_at("Paragraphs") + # address + while "PromptScreen" not in layout.all_components(): + layout = self.debug.swipe_up(wait=True) + self.debug.synchronize_at("PromptScreen") + # tap to confirm self.debug.press_yes() @@ -1133,7 +1199,7 @@ class InputFlowBip39ResetBackup(InputFlowBase): self.mnemonic = None # NOTE: same as above, just two more YES - def input_flow_common(self) -> BRGeneratorType: + def input_flow_tt(self) -> BRGeneratorType: # 1. Confirm Reset # 2. Backup your seed # 3. Confirm warning @@ -1142,6 +1208,24 @@ class InputFlowBip39ResetBackup(InputFlowBase): # mnemonic phrases and rest self.mnemonic = yield from get_mnemonic_and_confirm_success(self.debug) + def input_flow_tr(self) -> BRGeneratorType: + # 1. Confirm Reset + # 2. Backup your seed + # 3. Confirm warning + yield from click_through(self.debug, screens=3, code=B.ResetDevice) + + # mnemonic phrases and rest + self.mnemonic = yield from get_mnemonic_and_confirm_success(self.debug) + + def input_flow_t3t1(self) -> BRGeneratorType: + # 1. Confirm Reset x3 + # 2. Backup your seed + # 3. Confirm warning + yield from click_through(self.debug, screens=3, code=B.ResetDevice) + + # mnemonic phrases and rest + self.mnemonic = yield from get_mnemonic_and_confirm_success(self.debug) + class InputFlowBip39ResetPIN(InputFlowBase): def __init__(self, client: Client):