mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-17 21:22:10 +00:00
chore(core/rust): improve the design of TR's tutorial flow
[no changelog]
This commit is contained in:
parent
947e2ee24f
commit
13cb1ea4ce
@ -101,6 +101,11 @@ impl<'a, T: StringType + Clone + 'a> OpTextLayout<T> {
|
||||
// Try to fit text on the current page and if they do not fit,
|
||||
// return the appropriate OutOfBounds message
|
||||
|
||||
// Inserting the ellipsis at the very beginning of the text if needed
|
||||
// (just once for the first Op::Text on the non-first page).
|
||||
self.layout.continues_from_prev_page =
|
||||
skip_bytes > 0 && total_processed_chars == 0;
|
||||
|
||||
let fit = self.layout.layout_text(text.as_ref(), cursor, sink);
|
||||
|
||||
match fit {
|
||||
|
@ -29,6 +29,7 @@ where
|
||||
buttons: Child<ButtonController<T>>,
|
||||
page_counter: usize,
|
||||
return_confirmed_index: bool,
|
||||
show_scrollbar: bool,
|
||||
}
|
||||
|
||||
impl<F, T> Flow<F, T>
|
||||
@ -52,6 +53,7 @@ where
|
||||
buttons: Child::new(ButtonController::new(ButtonLayout::empty())),
|
||||
page_counter: 0,
|
||||
return_confirmed_index: false,
|
||||
show_scrollbar: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +70,12 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
/// Show scrollbar or not.
|
||||
pub fn with_scrollbar(mut self, show_scrollbar: bool) -> Self {
|
||||
self.show_scrollbar = show_scrollbar;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn confirmed_index(&self) -> Option<usize> {
|
||||
self.return_confirmed_index.then_some(self.page_counter)
|
||||
}
|
||||
@ -203,8 +211,11 @@ where
|
||||
// (scrollbar will be active - counting pages - even when not placed and
|
||||
// painted)
|
||||
if self.title.is_some() {
|
||||
let (title_area, scrollbar_area) =
|
||||
title_area.split_right(self.scrollbar.inner().overall_width() + SCROLLBAR_SPACE);
|
||||
let (title_area, scrollbar_area) = if self.show_scrollbar {
|
||||
title_area.split_right(self.scrollbar.inner().overall_width() + SCROLLBAR_SPACE)
|
||||
} else {
|
||||
(title_area, Rect::zero())
|
||||
};
|
||||
|
||||
self.title.place(title_area);
|
||||
self.title_area = title_area;
|
||||
@ -265,9 +276,11 @@ where
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.pad.paint();
|
||||
// Scrollbars are painted only with a title
|
||||
// Scrollbars are painted only with a title and when requested
|
||||
if self.title.is_some() {
|
||||
self.scrollbar.paint();
|
||||
if self.show_scrollbar {
|
||||
self.scrollbar.paint();
|
||||
}
|
||||
self.title.paint();
|
||||
}
|
||||
self.buttons.paint();
|
||||
|
@ -31,8 +31,7 @@ use crate::{
|
||||
},
|
||||
ComponentExt, FormattedText, LineBreaking, Timeout,
|
||||
},
|
||||
display::{self},
|
||||
geometry::Alignment,
|
||||
display, geometry,
|
||||
layout::{
|
||||
obj::{ComponentMsgObj, LayoutObj},
|
||||
result::{CANCELLED, CONFIRMED, INFO},
|
||||
@ -641,22 +640,16 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
|
||||
}
|
||||
|
||||
/// General pattern of most tutorial screens.
|
||||
/// (title, text, btn_layout, btn_actions)
|
||||
/// (title, text, btn_layout, btn_actions, text_y_offset)
|
||||
fn tutorial_screen(
|
||||
title: &'static str,
|
||||
text: &'static str,
|
||||
btn_layout: ButtonLayout<StrBuffer>,
|
||||
btn_actions: ButtonActions,
|
||||
) -> Page<StrBuffer> {
|
||||
let mut ops = OpTextLayout::<StrBuffer>::new(theme::TEXT_NORMAL);
|
||||
// Add title if present
|
||||
if !title.is_empty() {
|
||||
ops = ops.text_bold(title.into()).newline().newline_half()
|
||||
}
|
||||
ops = ops.text_normal(text.into());
|
||||
|
||||
let formatted = FormattedText::new(ops);
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
let ops = OpTextLayout::<StrBuffer>::new(theme::TEXT_NORMAL).text_normal(text.into());
|
||||
let formatted = FormattedText::new(ops).vertically_aligned(geometry::Alignment::Center);
|
||||
Page::new(btn_layout, btn_actions, formatted).with_title(title.into())
|
||||
}
|
||||
|
||||
extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
@ -674,15 +667,15 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
0 => {
|
||||
tutorial_screen(
|
||||
"HELLO",
|
||||
"Welcome to Trezor.\nPress right to continue.",
|
||||
ButtonLayout::text_none_arrow("SKIP".into()),
|
||||
"Welcome to Trezor. Press right to continue.",
|
||||
ButtonLayout::cancel_none_arrow(),
|
||||
ButtonActions::last_none_next(),
|
||||
)
|
||||
},
|
||||
1 => {
|
||||
tutorial_screen(
|
||||
"",
|
||||
"Use Trezor by clicking left and right buttons.\n\nContinue right.",
|
||||
"Use Trezor by\nclicking the left and right buttons.\n\rContinue right.",
|
||||
ButtonLayout::arrow_none_arrow(),
|
||||
ButtonActions::prev_none_next(),
|
||||
)
|
||||
@ -690,7 +683,7 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
2 => {
|
||||
tutorial_screen(
|
||||
"HOLD TO CONFIRM",
|
||||
"Press and hold right to approve important operations.",
|
||||
"Press and hold the right button to\napprove important operations.",
|
||||
ButtonLayout::arrow_none_htc("HOLD TO CONFIRM".into()),
|
||||
ButtonActions::prev_none_next(),
|
||||
)
|
||||
@ -698,7 +691,7 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
3 => {
|
||||
tutorial_screen(
|
||||
"SCREEN SCROLL",
|
||||
"Press right to scroll down to read all content when text\ndoesn't fit on one screen. Press left to scroll up.",
|
||||
"Press right to scroll down to read all content when text doesn't fit on one screen.\n\rPress left to scroll up.",
|
||||
ButtonLayout::arrow_none_text("CONTINUE".into()),
|
||||
ButtonActions::prev_none_next(),
|
||||
)
|
||||
@ -706,33 +699,24 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
4 => {
|
||||
tutorial_screen(
|
||||
"CONFIRM",
|
||||
"Press both left and right at the same time to confirm.",
|
||||
"Press both left and right at the same\ntime to confirm.",
|
||||
ButtonLayout::none_armed_none("CONFIRM".into()),
|
||||
ButtonActions::prev_next_none(),
|
||||
)
|
||||
},
|
||||
// This page is special
|
||||
5 => {
|
||||
let ops = OpTextLayout::<StrBuffer>::new(theme::TEXT_NORMAL)
|
||||
.newline()
|
||||
.text_normal("Tutorial complete.".into())
|
||||
.newline()
|
||||
.newline()
|
||||
.alignment(Alignment::Center)
|
||||
.text_bold("You're ready to\nuse Trezor.".into());
|
||||
let formatted = FormattedText::new(ops);
|
||||
|
||||
Page::new(
|
||||
ButtonLayout::text_none_text("AGAIN".into(), "FINISH".into()),
|
||||
tutorial_screen(
|
||||
"TUTORIAL COMPLETE",
|
||||
"You're ready to\nuse Trezor.",
|
||||
ButtonLayout::text_none_text("AGAIN".into(), "CONTINUE".into()),
|
||||
ButtonActions::beginning_none_confirm(),
|
||||
formatted,
|
||||
)
|
||||
},
|
||||
6 => {
|
||||
tutorial_screen(
|
||||
"SKIP TUTORIAL",
|
||||
"Are you sure you want to skip the tutorial?",
|
||||
ButtonLayout::cancel_none_text("SKIP".into()),
|
||||
"Are you sure you\nwant to skip the tutorial?",
|
||||
ButtonLayout::arrow_none_text("SKIP".into()),
|
||||
ButtonActions::beginning_none_cancel(),
|
||||
)
|
||||
},
|
||||
@ -742,7 +726,11 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
|
||||
let pages = FlowPages::new(get_page, PAGE_COUNT);
|
||||
|
||||
let obj = LayoutObj::new(Flow::new(pages))?;
|
||||
let obj = LayoutObj::new(
|
||||
Flow::new(pages)
|
||||
.with_scrollbar(false)
|
||||
.with_common_title("HELLO".into()),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
|
@ -49,7 +49,7 @@ def go_through_tutorial(debug: "DebugLink") -> None:
|
||||
debug.press_right(wait=True)
|
||||
debug.press_right(wait=True)
|
||||
layout = debug.press_middle(wait=True)
|
||||
assert "Tutorial complete" in layout.text_content()
|
||||
assert layout.title() == "TUTORIAL COMPLETE"
|
||||
|
||||
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
@ -66,8 +66,6 @@ def test_tutorial_finish(device_handler: "BackgroundDeviceHandler"):
|
||||
def test_tutorial_skip(device_handler: "BackgroundDeviceHandler"):
|
||||
with prepare_tutorial_and_cancel_after_it(device_handler) as debug:
|
||||
# SKIP
|
||||
# debug.press_left()
|
||||
# debug.press_right()
|
||||
debug.press_left(wait=True)
|
||||
debug.press_right(wait=True)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user