mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-26 18:02:35 +00:00
feat(eckhart): implement basic UiFirmware fns
- confirm_action, confirm_value - few show_xyz - provisional homescreen
This commit is contained in:
parent
ea4d704a8a
commit
0696090691
@ -1667,7 +1667,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
|
|||||||
/// title: str,
|
/// title: str,
|
||||||
/// button: str,
|
/// button: str,
|
||||||
/// description: str = "",
|
/// description: str = "",
|
||||||
/// allow_cancel: bool = True,
|
/// allow_cancel: bool = False,
|
||||||
/// time_ms: int = 0,
|
/// time_ms: int = 0,
|
||||||
/// ) -> LayoutObj[UiResult]:
|
/// ) -> LayoutObj[UiResult]:
|
||||||
/// """Success modal. No buttons shown when `button` is empty string."""
|
/// """Success modal. No buttons shown when `button` is empty string."""
|
||||||
|
@ -12,6 +12,7 @@ use super::{
|
|||||||
fonts,
|
fonts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const CONFIRM_HOLD_DURATION: Duration = Duration::from_millis(1500);
|
||||||
pub const ERASE_HOLD_DURATION: Duration = Duration::from_millis(1500);
|
pub const ERASE_HOLD_DURATION: Duration = Duration::from_millis(1500);
|
||||||
|
|
||||||
// Color palette.
|
// Color palette.
|
||||||
@ -136,6 +137,12 @@ pub const TEXT_MONO_LIGHT: TextStyle = TextStyle::new(
|
|||||||
GREY_EXTRA_LIGHT,
|
GREY_EXTRA_LIGHT,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Decide the text style of chunkified text according to its length.
|
||||||
|
pub fn get_chunkified_text_style(_character_length: usize) -> &'static TextStyle {
|
||||||
|
// TODO: implement properly for Eckhart, see Delizia implemenation
|
||||||
|
&TEXT_MONO_MEDIUM
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn label_title_main() -> TextStyle {
|
pub const fn label_title_main() -> TextStyle {
|
||||||
TEXT_SMALL
|
TEXT_SMALL
|
||||||
}
|
}
|
||||||
@ -147,7 +154,7 @@ pub const fn button_default() -> ButtonStyleSheet {
|
|||||||
font: fonts::FONT_SATOSHI_MEDIUM_26,
|
font: fonts::FONT_SATOSHI_MEDIUM_26,
|
||||||
text_color: GREY_LIGHT,
|
text_color: GREY_LIGHT,
|
||||||
button_color: BG,
|
button_color: BG,
|
||||||
icon_color: FG,
|
icon_color: GREY_LIGHT,
|
||||||
background_color: BG,
|
background_color: BG,
|
||||||
},
|
},
|
||||||
active: &ButtonStyle {
|
active: &ButtonStyle {
|
||||||
@ -167,6 +174,32 @@ pub const fn button_default() -> ButtonStyleSheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn button_confirm() -> ButtonStyleSheet {
|
||||||
|
ButtonStyleSheet {
|
||||||
|
normal: &ButtonStyle {
|
||||||
|
font: fonts::FONT_SATOSHI_MEDIUM_26,
|
||||||
|
text_color: GREEN_LIGHT,
|
||||||
|
button_color: BG,
|
||||||
|
icon_color: GREEN_LIGHT,
|
||||||
|
background_color: BG,
|
||||||
|
},
|
||||||
|
active: &ButtonStyle {
|
||||||
|
font: fonts::FONT_SATOSHI_MEDIUM_26,
|
||||||
|
text_color: GREEN,
|
||||||
|
button_color: GREY_SUPER_DARK,
|
||||||
|
icon_color: GREEN,
|
||||||
|
background_color: BG,
|
||||||
|
},
|
||||||
|
disabled: &ButtonStyle {
|
||||||
|
font: fonts::FONT_SATOSHI_MEDIUM_26,
|
||||||
|
text_color: GREY_LIGHT,
|
||||||
|
button_color: GREY_DARK,
|
||||||
|
icon_color: GREY_LIGHT,
|
||||||
|
background_color: GREY_DARK,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub const fn button_header() -> ButtonStyleSheet {
|
pub const fn button_header() -> ButtonStyleSheet {
|
||||||
ButtonStyleSheet {
|
ButtonStyleSheet {
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
io::BinaryData,
|
io::BinaryData,
|
||||||
micropython::{gc::Gc, list::List, obj::Obj},
|
micropython::{gc::Gc, iter::IterBuf, list::List, obj::Obj, util},
|
||||||
strutil::TString,
|
strutil::TString,
|
||||||
|
translations::TR,
|
||||||
ui::{
|
ui::{
|
||||||
component::Empty,
|
component::{
|
||||||
|
text::{
|
||||||
|
op::OpTextLayout,
|
||||||
|
paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt},
|
||||||
|
},
|
||||||
|
Empty, FormattedText,
|
||||||
|
},
|
||||||
layout::{
|
layout::{
|
||||||
obj::{LayoutMaybeTrace, LayoutObj, RootComponent},
|
obj::{LayoutMaybeTrace, LayoutObj, RootComponent},
|
||||||
util::RecoveryType,
|
util::{ConfirmValueParams, RecoveryType, StrOrBytes},
|
||||||
},
|
},
|
||||||
ui_firmware::{
|
ui_firmware::{
|
||||||
FirmwareUI, MAX_CHECKLIST_ITEMS, MAX_GROUP_SHARE_LINES, MAX_WORD_QUIZ_ITEMS,
|
FirmwareUI, MAX_CHECKLIST_ITEMS, MAX_GROUP_SHARE_LINES, MAX_WORD_QUIZ_ITEMS,
|
||||||
@ -17,25 +24,60 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
component::{ActionBar, Button, GenericScreen, Header, Hint},
|
component::{ActionBar, Button, Header, HeaderMsg, Hint, TextScreen},
|
||||||
theme, UIEckhart,
|
fonts, theme, UIEckhart,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl FirmwareUI for UIEckhart {
|
impl FirmwareUI for UIEckhart {
|
||||||
fn confirm_action(
|
fn confirm_action(
|
||||||
_title: TString<'static>,
|
title: TString<'static>,
|
||||||
_action: Option<TString<'static>>,
|
action: Option<TString<'static>>,
|
||||||
_description: Option<TString<'static>>,
|
description: Option<TString<'static>>,
|
||||||
_subtitle: Option<TString<'static>>,
|
_subtitle: Option<TString<'static>>,
|
||||||
_verb: Option<TString<'static>>,
|
verb: Option<TString<'static>>,
|
||||||
_verb_cancel: Option<TString<'static>>,
|
_verb_cancel: Option<TString<'static>>,
|
||||||
_hold: bool,
|
hold: bool,
|
||||||
_hold_danger: bool,
|
_hold_danger: bool,
|
||||||
_reverse: bool,
|
reverse: bool,
|
||||||
_prompt_screen: bool,
|
_prompt_screen: bool,
|
||||||
_prompt_title: Option<TString<'static>>,
|
_prompt_title: Option<TString<'static>>,
|
||||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
let action = action.unwrap_or("".into());
|
||||||
|
let description = description.unwrap_or("".into());
|
||||||
|
let formatted_text = {
|
||||||
|
let ops = if !reverse {
|
||||||
|
OpTextLayout::new(theme::TEXT_NORMAL)
|
||||||
|
.color(theme::GREY_LIGHT)
|
||||||
|
.text(action, fonts::FONT_SATOSHI_REGULAR_38)
|
||||||
|
.newline()
|
||||||
|
.color(theme::GREY)
|
||||||
|
.text(description, fonts::FONT_SATOSHI_REGULAR_22)
|
||||||
|
} else {
|
||||||
|
OpTextLayout::new(theme::TEXT_NORMAL)
|
||||||
|
.color(theme::GREY)
|
||||||
|
.text(description, fonts::FONT_SATOSHI_REGULAR_22)
|
||||||
|
.newline()
|
||||||
|
.color(theme::GREY_LIGHT)
|
||||||
|
.text(action, fonts::FONT_SATOSHI_REGULAR_38)
|
||||||
|
};
|
||||||
|
FormattedText::new(ops).vertically_centered()
|
||||||
|
};
|
||||||
|
|
||||||
|
let verb = verb.unwrap_or(TR::buttons__confirm.into());
|
||||||
|
let right_button = if hold {
|
||||||
|
Button::with_text(verb).with_long_press(theme::CONFIRM_HOLD_DURATION)
|
||||||
|
} else {
|
||||||
|
Button::with_text(verb)
|
||||||
|
};
|
||||||
|
let screen = TextScreen::new(formatted_text)
|
||||||
|
.with_header(Header::new(title).with_menu_button())
|
||||||
|
.with_hint(Hint::new_instruction(description, None))
|
||||||
|
.with_action_bar(ActionBar::new_double(
|
||||||
|
Button::with_icon(theme::ICON_CHEVRON_LEFT),
|
||||||
|
right_button,
|
||||||
|
));
|
||||||
|
let layout = RootComponent::new(screen);
|
||||||
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_address(
|
fn confirm_address(
|
||||||
@ -146,22 +188,65 @@ impl FirmwareUI for UIEckhart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_value(
|
fn confirm_value(
|
||||||
_title: TString<'static>,
|
title: TString<'static>,
|
||||||
_value: Obj,
|
value: Obj,
|
||||||
_description: Option<TString<'static>>,
|
description: Option<TString<'static>>,
|
||||||
_is_data: bool,
|
is_data: bool,
|
||||||
_extra: Option<TString<'static>>,
|
extra: Option<TString<'static>>,
|
||||||
_subtitle: Option<TString<'static>>,
|
_subtitle: Option<TString<'static>>,
|
||||||
_verb: Option<TString<'static>>,
|
verb: Option<TString<'static>>,
|
||||||
_verb_cancel: Option<TString<'static>>,
|
_verb_cancel: Option<TString<'static>>,
|
||||||
_info: bool,
|
info: bool,
|
||||||
_hold: bool,
|
hold: bool,
|
||||||
_chunkify: bool,
|
chunkify: bool,
|
||||||
_page_counter: bool,
|
page_counter: bool,
|
||||||
_prompt_screen: bool,
|
_prompt_screen: bool,
|
||||||
_cancel: bool,
|
cancel: bool,
|
||||||
) -> Result<Gc<LayoutObj>, Error> {
|
) -> Result<Gc<LayoutObj>, Error> {
|
||||||
Err::<Gc<LayoutObj>, Error>(Error::ValueError(c"not implemented"))
|
let paragraphs = ConfirmValueParams {
|
||||||
|
description: description.unwrap_or("".into()),
|
||||||
|
extra: extra.unwrap_or("".into()),
|
||||||
|
value: if value != Obj::const_none() {
|
||||||
|
value.try_into()?
|
||||||
|
} else {
|
||||||
|
StrOrBytes::Str("".into())
|
||||||
|
},
|
||||||
|
font: if chunkify {
|
||||||
|
let value: TString = value.try_into()?;
|
||||||
|
theme::get_chunkified_text_style(value.len())
|
||||||
|
} else if is_data {
|
||||||
|
&theme::TEXT_MONO_MEDIUM
|
||||||
|
} else {
|
||||||
|
&theme::TEXT_MEDIUM
|
||||||
|
},
|
||||||
|
description_font: &theme::TEXT_SMALL,
|
||||||
|
extra_font: &theme::TEXT_SMALL,
|
||||||
|
}
|
||||||
|
.into_paragraphs();
|
||||||
|
|
||||||
|
let verb = verb.unwrap_or(TR::buttons__confirm.into());
|
||||||
|
let right_button = if hold {
|
||||||
|
Button::with_text(verb).with_long_press(theme::CONFIRM_HOLD_DURATION)
|
||||||
|
} else {
|
||||||
|
Button::with_text(verb)
|
||||||
|
};
|
||||||
|
let header = if info {
|
||||||
|
Header::new(title)
|
||||||
|
.with_right_button(Button::with_icon(theme::ICON_INFO), HeaderMsg::Menu)
|
||||||
|
} else {
|
||||||
|
Header::new(title)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut screen = TextScreen::new(paragraphs)
|
||||||
|
.with_header(header)
|
||||||
|
.with_action_bar(ActionBar::new_double(
|
||||||
|
Button::with_icon(theme::ICON_CROSS),
|
||||||
|
right_button,
|
||||||
|
));
|
||||||
|
if page_counter {
|
||||||
|
screen = screen.with_hint(Hint::new_page_counter());
|
||||||
|
}
|
||||||
|
LayoutObj::new(screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_value_intro(
|
fn confirm_value_intro(
|
||||||
@ -369,12 +454,22 @@ impl FirmwareUI for UIEckhart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show_homescreen(
|
fn show_homescreen(
|
||||||
_label: TString<'static>,
|
label: TString<'static>,
|
||||||
_hold: bool,
|
_hold: bool,
|
||||||
_notification: Option<TString<'static>>,
|
notification: Option<TString<'static>>,
|
||||||
_notification_level: u8,
|
_notification_level: u8,
|
||||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
let paragraphs = ParagraphVecShort::from_iter([
|
||||||
|
Paragraph::new(&theme::TEXT_NORMAL, label),
|
||||||
|
Paragraph::new(
|
||||||
|
&theme::TEXT_NORMAL,
|
||||||
|
notification.unwrap_or(TString::empty()),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.into_paragraphs();
|
||||||
|
|
||||||
|
let layout = RootComponent::new(paragraphs);
|
||||||
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_info(
|
fn show_info(
|
||||||
@ -387,12 +482,31 @@ impl FirmwareUI for UIEckhart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show_info_with_cancel(
|
fn show_info_with_cancel(
|
||||||
_title: TString<'static>,
|
title: TString<'static>,
|
||||||
_items: Obj,
|
items: Obj,
|
||||||
_horizontal: bool,
|
_horizontal: bool,
|
||||||
_chunkify: bool,
|
chunkify: bool,
|
||||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
let mut paragraphs = ParagraphVecShort::new();
|
||||||
|
for para in IterBuf::new().try_iterate(items)? {
|
||||||
|
let [key, value]: [Obj; 2] = util::iter_into_array(para)?;
|
||||||
|
let key: TString = key.try_into()?;
|
||||||
|
let value: TString = value.try_into()?;
|
||||||
|
paragraphs.add(Paragraph::new(&theme::TEXT_MEDIUM, key).no_break());
|
||||||
|
if chunkify {
|
||||||
|
paragraphs.add(Paragraph::new(
|
||||||
|
theme::get_chunkified_text_style(value.len()),
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
paragraphs.add(Paragraph::new(&theme::TEXT_MONO_MEDIUM, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let screen = TextScreen::new(paragraphs.into_paragraphs())
|
||||||
|
.with_header(Header::new(title).with_close_button());
|
||||||
|
let layout = RootComponent::new(screen);
|
||||||
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_lockscreen(
|
fn show_lockscreen(
|
||||||
@ -403,8 +517,22 @@ impl FirmwareUI for UIEckhart {
|
|||||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_mismatch(_title: TString<'static>) -> Result<impl LayoutMaybeTrace, Error> {
|
fn show_mismatch(title: TString<'static>) -> Result<impl LayoutMaybeTrace, Error> {
|
||||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
let description: TString = TR::addr_mismatch__contact_support_at.into();
|
||||||
|
let url: TString = TR::addr_mismatch__support_url.into();
|
||||||
|
let button: TString = TR::buttons__quit.into();
|
||||||
|
|
||||||
|
let paragraphs = ParagraphVecShort::from_iter([
|
||||||
|
Paragraph::new(&theme::TEXT_REGULAR, description).centered(),
|
||||||
|
Paragraph::new(&theme::TEXT_MONO_MEDIUM, url).centered(),
|
||||||
|
])
|
||||||
|
.into_paragraphs();
|
||||||
|
let screen = TextScreen::new(paragraphs)
|
||||||
|
.with_header(Header::new(title))
|
||||||
|
.with_action_bar(ActionBar::new_single(Button::with_text(button)));
|
||||||
|
|
||||||
|
let layout = RootComponent::new(screen);
|
||||||
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_progress(
|
fn show_progress(
|
||||||
@ -447,35 +575,82 @@ impl FirmwareUI for UIEckhart {
|
|||||||
|
|
||||||
fn show_simple(
|
fn show_simple(
|
||||||
text: TString<'static>,
|
text: TString<'static>,
|
||||||
_title: Option<TString<'static>>,
|
title: Option<TString<'static>>,
|
||||||
_button: Option<TString<'static>>,
|
button: Option<TString<'static>>,
|
||||||
) -> Result<Gc<LayoutObj>, Error> {
|
) -> Result<Gc<LayoutObj>, Error> {
|
||||||
Err::<Gc<LayoutObj>, Error>(Error::ValueError(c"not implemented"))
|
let paragraphs = Paragraph::new(&theme::TEXT_REGULAR, text).into_paragraphs();
|
||||||
|
|
||||||
|
let mut screen = TextScreen::new(paragraphs);
|
||||||
|
if let Some(title) = title {
|
||||||
|
screen = screen.with_header(Header::new(title));
|
||||||
|
}
|
||||||
|
if let Some(button) = button {
|
||||||
|
screen = screen.with_action_bar(ActionBar::new_single(Button::with_text(button)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj = LayoutObj::new(screen)?;
|
||||||
|
Ok(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_success(
|
fn show_success(
|
||||||
_title: TString<'static>,
|
title: TString<'static>,
|
||||||
_button: TString<'static>,
|
button: TString<'static>,
|
||||||
_description: TString<'static>,
|
description: TString<'static>,
|
||||||
_allow_cancel: bool,
|
allow_cancel: bool,
|
||||||
_time_ms: u32,
|
_time_ms: u32,
|
||||||
) -> Result<Gc<LayoutObj>, Error> {
|
) -> Result<Gc<LayoutObj>, Error> {
|
||||||
Err::<Gc<LayoutObj>, Error>(Error::ValueError(c"not implemented"))
|
let paragraphs = Paragraph::new(&theme::TEXT_REGULAR, description).into_paragraphs();
|
||||||
|
let header = Header::new(title).with_icon(theme::ICON_DONE, theme::GREEN_LIGHT);
|
||||||
|
let action_bar = if allow_cancel {
|
||||||
|
ActionBar::new_double(
|
||||||
|
Button::with_icon(theme::ICON_CROSS),
|
||||||
|
Button::with_text(button),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ActionBar::new_single(Button::with_text(button))
|
||||||
|
};
|
||||||
|
let screen = TextScreen::new(paragraphs)
|
||||||
|
.with_header(header)
|
||||||
|
.with_action_bar(action_bar);
|
||||||
|
let layout = LayoutObj::new(screen)?;
|
||||||
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_wait_text(_text: TString<'static>) -> Result<impl LayoutMaybeTrace, Error> {
|
fn show_wait_text(text: TString<'static>) -> Result<impl LayoutMaybeTrace, Error> {
|
||||||
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented"))
|
let paragraphs = Paragraph::new(&theme::TEXT_REGULAR, text).into_paragraphs();
|
||||||
|
let screen = TextScreen::new(paragraphs);
|
||||||
|
let layout = RootComponent::new(screen);
|
||||||
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_warning(
|
fn show_warning(
|
||||||
_title: TString<'static>,
|
title: TString<'static>,
|
||||||
_button: TString<'static>,
|
button: TString<'static>,
|
||||||
_value: TString<'static>,
|
value: TString<'static>,
|
||||||
_description: TString<'static>,
|
description: TString<'static>,
|
||||||
_allow_cancel: bool,
|
allow_cancel: bool,
|
||||||
_danger: bool,
|
danger: bool, // TODO: review if `danger` needed in all layouts since we have show_danger
|
||||||
) -> Result<Gc<LayoutObj>, Error> {
|
) -> Result<Gc<LayoutObj>, Error> {
|
||||||
Err::<Gc<LayoutObj>, Error>(Error::ValueError(c"not implemented"))
|
let paragraphs = ParagraphVecShort::from_iter([
|
||||||
|
Paragraph::new(&theme::TEXT_SMALL, description),
|
||||||
|
Paragraph::new(&theme::TEXT_REGULAR, value),
|
||||||
|
])
|
||||||
|
.into_paragraphs();
|
||||||
|
|
||||||
|
let header = Header::new(title).with_icon(theme::ICON_INFO, theme::GREEN_LIGHT);
|
||||||
|
let action_bar = if allow_cancel {
|
||||||
|
ActionBar::new_double(
|
||||||
|
Button::with_icon(theme::ICON_CROSS),
|
||||||
|
Button::with_text(button),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ActionBar::new_single(Button::with_text(button))
|
||||||
|
};
|
||||||
|
let screen = TextScreen::new(paragraphs)
|
||||||
|
.with_header(header)
|
||||||
|
.with_action_bar(action_bar);
|
||||||
|
let layout = LayoutObj::new(screen)?;
|
||||||
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tutorial() -> Result<impl LayoutMaybeTrace, Error> {
|
fn tutorial() -> Result<impl LayoutMaybeTrace, Error> {
|
||||||
|
@ -351,9 +351,9 @@ def show_success(
|
|||||||
) -> Awaitable[None]:
|
) -> Awaitable[None]:
|
||||||
return raise_if_not_confirmed(
|
return raise_if_not_confirmed(
|
||||||
trezorui_api.show_success(
|
trezorui_api.show_success(
|
||||||
title=content,
|
title=subheader if subheader else "",
|
||||||
button="",
|
button=button if button else "",
|
||||||
description=subheader if subheader else "",
|
description=content,
|
||||||
),
|
),
|
||||||
br_name,
|
br_name,
|
||||||
ButtonRequestType.Success,
|
ButtonRequestType.Success,
|
||||||
|
Loading…
Reference in New Issue
Block a user