mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-12 14:16:06 +00:00
feat(eckhart): show danger flow
This commit is contained in:
parent
5e8a75619e
commit
2b06ba21bd
@ -323,6 +323,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_max_feerate;
|
||||
MP_QSTR_max_len;
|
||||
MP_QSTR_max_rounds;
|
||||
MP_QSTR_menu_title;
|
||||
MP_QSTR_message;
|
||||
MP_QSTR_min_count;
|
||||
MP_QSTR_misc__decrypt_value;
|
||||
|
@ -736,12 +736,16 @@ extern "C" fn new_show_danger(n_args: usize, args: *const Obj, kwargs: *mut Map)
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
||||
let value: TString = kwargs.get_or(Qstr::MP_QSTR_value, "".into())?;
|
||||
let menu_title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_menu_title)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let verb_cancel: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_verb_cancel)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
|
||||
let layout = ModelUI::show_danger(title, description, value, verb_cancel)?;
|
||||
let layout = ModelUI::show_danger(title, description, value, menu_title, verb_cancel)?;
|
||||
Ok(LayoutObj::new_root(layout)?.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
@ -1518,6 +1522,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
|
||||
/// title: str,
|
||||
/// description: str,
|
||||
/// value: str = "",
|
||||
/// menu_title: str | None = None,
|
||||
/// verb_cancel: str | None = None,
|
||||
/// ) -> LayoutObj[UiResult]:
|
||||
/// """Warning modal that makes it easier to cancel than to continue."""
|
||||
|
@ -815,6 +815,7 @@ impl FirmwareUI for UIBolt {
|
||||
_title: TString<'static>,
|
||||
_description: TString<'static>,
|
||||
_value: TString<'static>,
|
||||
_menu_title: Option<TString<'static>>,
|
||||
_verb_cancel: Option<TString<'static>>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"show_danger not supported"))
|
||||
|
@ -986,6 +986,7 @@ impl FirmwareUI for UICaesar {
|
||||
_title: TString<'static>,
|
||||
_description: TString<'static>,
|
||||
_value: TString<'static>,
|
||||
_menu_title: Option<TString<'static>>,
|
||||
_verb_cancel: Option<TString<'static>>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"show_danger not supported"))
|
||||
|
@ -829,6 +829,7 @@ impl FirmwareUI for UIDelizia {
|
||||
title: TString<'static>,
|
||||
description: TString<'static>,
|
||||
value: TString<'static>,
|
||||
_menu_title: Option<TString<'static>>,
|
||||
verb_cancel: Option<TString<'static>>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||
let flow = flow::show_danger::new_show_danger(title, description, value, verb_cancel)?;
|
||||
|
@ -2,10 +2,12 @@ pub mod confirm_reset;
|
||||
pub mod get_address;
|
||||
pub mod prompt_backup;
|
||||
pub mod request_passphrase;
|
||||
pub mod show_danger;
|
||||
pub mod show_share_words;
|
||||
|
||||
pub use confirm_reset::new_confirm_reset;
|
||||
pub use get_address::GetAddress;
|
||||
pub use prompt_backup::PromptBackup;
|
||||
pub use request_passphrase::RequestPassphrase;
|
||||
pub use show_danger::ShowDanger;
|
||||
pub use show_share_words::new_show_share_words_flow;
|
||||
|
137
core/embed/rust/src/ui/layout_eckhart/flow/show_danger.rs
Normal file
137
core/embed/rust/src/ui/layout_eckhart/flow/show_danger.rs
Normal file
@ -0,0 +1,137 @@
|
||||
use crate::{
|
||||
error,
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{
|
||||
text::paragraphs::{Paragraph, ParagraphSource},
|
||||
ComponentExt,
|
||||
},
|
||||
flow::{
|
||||
base::{Decision, DecisionBuilder as _},
|
||||
FlowController, FlowMsg, SwipeFlow,
|
||||
},
|
||||
geometry::{Alignment, Direction, LinearPlacement, Offset},
|
||||
},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
component::Button,
|
||||
firmware::{
|
||||
ActionBar, Header, HeaderMsg, TextScreen, TextScreenMsg, VerticalMenu, VerticalMenuScreen,
|
||||
VerticalMenuScreenMsg,
|
||||
},
|
||||
theme,
|
||||
};
|
||||
|
||||
const TIMEOUT_MS: u32 = 2000;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ShowDanger {
|
||||
Message,
|
||||
Menu,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
impl FlowController for ShowDanger {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: Direction) -> Decision {
|
||||
match (self, direction) {
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> Decision {
|
||||
match (self, msg) {
|
||||
(Self::Message, FlowMsg::Info) => Self::Menu.goto(),
|
||||
(Self::Message, FlowMsg::Cancelled) => Self::Cancelled.goto(),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Menu, FlowMsg::Choice(_)) => Self::Cancelled.goto(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Message.goto(),
|
||||
(Self::Cancelled, _) => self.return_msg(FlowMsg::Cancelled),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_show_danger(
|
||||
title: TString<'static>,
|
||||
description: TString<'static>,
|
||||
value: TString<'static>,
|
||||
menu_title: Option<TString<'static>>,
|
||||
verb_cancel: Option<TString<'static>>,
|
||||
) -> Result<SwipeFlow, error::Error> {
|
||||
let verb_cancel = verb_cancel.unwrap_or(TR::words__cancel_and_exit.into());
|
||||
|
||||
// Message
|
||||
let paragraphs = [
|
||||
Paragraph::new(&theme::TEXT_REGULAR, description),
|
||||
Paragraph::new(&theme::TEXT_MONO_EXTRA_LIGHT, value),
|
||||
]
|
||||
.into_paragraphs()
|
||||
.with_placement(LinearPlacement::vertical().with_spacing(35));
|
||||
|
||||
let content_message = TextScreen::new(paragraphs)
|
||||
.with_header(
|
||||
Header::new(title)
|
||||
.with_menu_button()
|
||||
.with_icon(theme::ICON_INFO, theme::ORANGE)
|
||||
.with_text_style(theme::label_title_danger()),
|
||||
)
|
||||
.with_action_bar(ActionBar::new_single(Button::with_text(verb_cancel)))
|
||||
.map(|msg| match msg {
|
||||
TextScreenMsg::Menu => Some(FlowMsg::Info),
|
||||
TextScreenMsg::Confirmed => Some(FlowMsg::Cancelled),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
// Menu
|
||||
let content_menu = VerticalMenuScreen::new(
|
||||
VerticalMenu::empty()
|
||||
.with_separators()
|
||||
.item(
|
||||
Button::with_text(verb_cancel)
|
||||
.styled(theme::menu_item_title())
|
||||
.with_text_align(Alignment::Start)
|
||||
.with_content_offset(Offset::x(12)),
|
||||
)
|
||||
.item(
|
||||
Button::with_text(TR::words__continue_anyway.into())
|
||||
.styled(theme::menu_item_title_orange())
|
||||
.with_text_align(Alignment::Start)
|
||||
.with_content_offset(Offset::x(12)),
|
||||
),
|
||||
)
|
||||
.with_header(
|
||||
Header::new(menu_title.unwrap_or("".into()))
|
||||
.with_right_button(Button::with_icon(theme::ICON_CROSS), HeaderMsg::Cancelled),
|
||||
)
|
||||
.map(|msg| match msg {
|
||||
VerticalMenuScreenMsg::Selected(i) => Some(FlowMsg::Choice(i)),
|
||||
VerticalMenuScreenMsg::Close => Some(FlowMsg::Cancelled),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
// Cancelled
|
||||
let content_cancelled = TextScreen::new(
|
||||
Paragraph::new(&theme::TEXT_REGULAR, TR::words__operation_cancelled)
|
||||
.into_paragraphs()
|
||||
.with_placement(LinearPlacement::vertical()),
|
||||
)
|
||||
.with_header(Header::new(TR::words__title_done.into()).with_icon(theme::ICON_DONE, theme::GREY))
|
||||
.with_action_bar(ActionBar::new_timeout(
|
||||
Button::with_text(TR::instructions__continue_in_app.into()),
|
||||
TIMEOUT_MS,
|
||||
))
|
||||
.map(|_| Some(FlowMsg::Confirmed));
|
||||
|
||||
let mut res = SwipeFlow::new(&ShowDanger::Message)?;
|
||||
res.add_page(&ShowDanger::Message, content_message)?
|
||||
.add_page(&ShowDanger::Menu, content_menu)?
|
||||
.add_page(&ShowDanger::Cancelled, content_cancelled)?;
|
||||
Ok(res)
|
||||
}
|
@ -39,10 +39,10 @@ pub const TEXT_BIG: TextStyle = TextStyle::new(
|
||||
/// TT Satoshi Regular - 38 (Screen text, Menu item label)
|
||||
pub const TEXT_REGULAR: TextStyle = TextStyle::new(
|
||||
fonts::FONT_SATOSHI_REGULAR_38,
|
||||
GREY_EXTRA_LIGHT,
|
||||
GREY_LIGHT,
|
||||
BG,
|
||||
GREY_EXTRA_LIGHT,
|
||||
GREY_EXTRA_LIGHT,
|
||||
GREY_LIGHT,
|
||||
GREY_LIGHT,
|
||||
);
|
||||
/// TT Satoshi Medium - 26 (Screen text, Button label, Input value)
|
||||
pub const TEXT_MEDIUM: TextStyle = TextStyle::new(
|
||||
@ -105,6 +105,14 @@ pub fn get_chunkified_text_style(_character_length: usize) -> &'static TextStyle
|
||||
&TEXT_MONO_ADDRESS_CHUNKS
|
||||
}
|
||||
|
||||
pub const TEXT_MONO_EXTRA_LIGHT: TextStyle = TextStyle::new(
|
||||
fonts::FONT_MONO_LIGHT_30,
|
||||
GREY_EXTRA_LIGHT,
|
||||
BG,
|
||||
GREY_EXTRA_LIGHT,
|
||||
GREY_EXTRA_LIGHT,
|
||||
);
|
||||
|
||||
// Macro for styles differing only in text color
|
||||
macro_rules! label_title {
|
||||
($color:expr) => {
|
||||
|
@ -498,12 +498,15 @@ impl FirmwareUI for UIEckhart {
|
||||
}
|
||||
|
||||
fn show_danger(
|
||||
_title: TString<'static>,
|
||||
_description: TString<'static>,
|
||||
_value: TString<'static>,
|
||||
_verb_cancel: Option<TString<'static>>,
|
||||
title: TString<'static>,
|
||||
description: TString<'static>,
|
||||
value: TString<'static>,
|
||||
menu_title: Option<TString<'static>>,
|
||||
verb_cancel: Option<TString<'static>>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
||||
let flow =
|
||||
flow::show_danger::new_show_danger(title, description, value, menu_title, verb_cancel)?;
|
||||
Ok(flow)
|
||||
}
|
||||
|
||||
fn show_error(
|
||||
|
@ -278,6 +278,7 @@ pub trait FirmwareUI {
|
||||
title: TString<'static>,
|
||||
description: TString<'static>,
|
||||
value: TString<'static>,
|
||||
menu_title: Option<TString<'static>>,
|
||||
verb_cancel: Option<TString<'static>>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error>;
|
||||
|
||||
|
@ -491,6 +491,7 @@ def show_danger(
|
||||
title: str,
|
||||
description: str,
|
||||
value: str = "",
|
||||
menu_title: str | None = None,
|
||||
verb_cancel: str | None = None,
|
||||
) -> LayoutObj[UiResult]:
|
||||
"""Warning modal that makes it easier to cancel than to continue."""
|
||||
|
Loading…
Reference in New Issue
Block a user