mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-09 16:18:10 +00:00
feat(core/mercury): change FW update UI
This commit changes the UI of confirming interaction-less firmware update.
This commit is contained in:
parent
53799cdee8
commit
f41176af02
1
core/.changelog.d/4030.added
Normal file
1
core/.changelog.d/4030.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
[T3T1] New UI of confirming interaction-less firmware update
|
@ -0,0 +1,144 @@
|
|||||||
|
use crate::{
|
||||||
|
error,
|
||||||
|
micropython::{map::Map, obj::Obj, qstr::Qstr, util},
|
||||||
|
strutil::TString,
|
||||||
|
translations::TR,
|
||||||
|
ui::{
|
||||||
|
component::{
|
||||||
|
swipe_detect::SwipeSettings,
|
||||||
|
text::paragraphs::{Paragraph, Paragraphs},
|
||||||
|
ComponentExt, SwipeDirection,
|
||||||
|
},
|
||||||
|
flow::{
|
||||||
|
base::{DecisionBuilder as _, StateChange},
|
||||||
|
FlowMsg, FlowState, SwipeFlow,
|
||||||
|
},
|
||||||
|
layout::obj::LayoutObj,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::{
|
||||||
|
component::{
|
||||||
|
CancelInfoConfirmMsg, Frame, FrameMsg, PromptScreen, SwipeContent, VerticalMenu,
|
||||||
|
VerticalMenuChoiceMsg,
|
||||||
|
},
|
||||||
|
theme,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ConfirmFirmwareUpdate {
|
||||||
|
Intro,
|
||||||
|
Menu,
|
||||||
|
Fingerprint,
|
||||||
|
Confirm,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowState for ConfirmFirmwareUpdate {
|
||||||
|
#[inline]
|
||||||
|
fn index(&'static self) -> usize {
|
||||||
|
*self as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||||
|
match (self, direction) {
|
||||||
|
(Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||||
|
(Self::Intro, SwipeDirection::Up) => Self::Confirm.swipe(direction),
|
||||||
|
(Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||||
|
(Self::Fingerprint, SwipeDirection::Right) => Self::Menu.swipe(direction),
|
||||||
|
(Self::Confirm, SwipeDirection::Down) => Self::Intro.swipe(direction),
|
||||||
|
(Self::Confirm, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||||
|
match (self, msg) {
|
||||||
|
(Self::Intro, FlowMsg::Info) => Self::Menu.transit(),
|
||||||
|
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||||
|
(Self::Menu, FlowMsg::Choice(0)) => Self::Fingerprint.transit(),
|
||||||
|
(Self::Menu, FlowMsg::Choice(1)) => self.return_msg(FlowMsg::Cancelled),
|
||||||
|
(Self::Fingerprint, FlowMsg::Cancelled) => Self::Menu.transit(),
|
||||||
|
(Self::Confirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
|
||||||
|
(Self::Confirm, FlowMsg::Info) => Self::Menu.transit(),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
pub extern "C" fn new_confirm_firmware_update(
|
||||||
|
n_args: usize,
|
||||||
|
args: *const Obj,
|
||||||
|
kwargs: *mut Map,
|
||||||
|
) -> Obj {
|
||||||
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ConfirmFirmwareUpdate::new_obj) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfirmFirmwareUpdate {
|
||||||
|
fn new_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
||||||
|
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
||||||
|
let fingerprint: TString = kwargs.get(Qstr::MP_QSTR_fingerprint)?.try_into()?;
|
||||||
|
|
||||||
|
let paragraphs = Paragraphs::new(Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, description));
|
||||||
|
let content_intro = Frame::left_aligned(
|
||||||
|
TR::firmware_update__title.into(),
|
||||||
|
SwipeContent::new(paragraphs),
|
||||||
|
)
|
||||||
|
.with_menu_button()
|
||||||
|
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||||
|
.with_swipe(SwipeDirection::Up, SwipeSettings::default())
|
||||||
|
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
|
||||||
|
.map(|msg| {
|
||||||
|
matches!(msg, FrameMsg::Button(CancelInfoConfirmMsg::Info)).then_some(FlowMsg::Info)
|
||||||
|
});
|
||||||
|
|
||||||
|
let content_menu = Frame::left_aligned(
|
||||||
|
TString::empty(),
|
||||||
|
VerticalMenu::empty()
|
||||||
|
.item(
|
||||||
|
theme::ICON_CHEVRON_RIGHT,
|
||||||
|
TR::firmware_update__title_fingerprint.into(),
|
||||||
|
)
|
||||||
|
.danger(theme::ICON_CANCEL, TR::buttons__cancel.into()),
|
||||||
|
)
|
||||||
|
.with_cancel_button()
|
||||||
|
.with_swipe(SwipeDirection::Right, SwipeSettings::immediate())
|
||||||
|
.map(|msg| match msg {
|
||||||
|
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
|
||||||
|
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
|
||||||
|
});
|
||||||
|
|
||||||
|
let paragraphs_fingerprint =
|
||||||
|
Paragraphs::new(Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, fingerprint));
|
||||||
|
let content_fingerprint = Frame::left_aligned(
|
||||||
|
TR::firmware_update__title_fingerprint.into(),
|
||||||
|
SwipeContent::new(paragraphs_fingerprint),
|
||||||
|
)
|
||||||
|
.with_cancel_button()
|
||||||
|
.with_swipe(SwipeDirection::Right, SwipeSettings::default())
|
||||||
|
.map(|msg| {
|
||||||
|
matches!(msg, FrameMsg::Button(CancelInfoConfirmMsg::Cancelled))
|
||||||
|
.then_some(FlowMsg::Cancelled)
|
||||||
|
});
|
||||||
|
|
||||||
|
let content_confirm = Frame::left_aligned(
|
||||||
|
TR::firmware_update__title.into(),
|
||||||
|
SwipeContent::new(PromptScreen::new_hold_to_confirm()),
|
||||||
|
)
|
||||||
|
.with_menu_button()
|
||||||
|
.with_footer(TR::instructions__hold_to_confirm.into(), None)
|
||||||
|
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
|
||||||
|
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
|
||||||
|
.map(|msg| match msg {
|
||||||
|
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
|
||||||
|
FrameMsg::Button(_) => Some(FlowMsg::Info),
|
||||||
|
});
|
||||||
|
|
||||||
|
let res = SwipeFlow::new(&ConfirmFirmwareUpdate::Intro)?
|
||||||
|
.with_page(&ConfirmFirmwareUpdate::Intro, content_intro)?
|
||||||
|
.with_page(&ConfirmFirmwareUpdate::Menu, content_menu)?
|
||||||
|
.with_page(&ConfirmFirmwareUpdate::Fingerprint, content_fingerprint)?
|
||||||
|
.with_page(&ConfirmFirmwareUpdate::Confirm, content_confirm)?;
|
||||||
|
Ok(LayoutObj::new(res)?.into())
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
pub mod confirm_action;
|
pub mod confirm_action;
|
||||||
|
pub mod confirm_firmware_update;
|
||||||
pub mod confirm_output;
|
pub mod confirm_output;
|
||||||
pub mod confirm_reset_create;
|
pub mod confirm_reset_create;
|
||||||
pub mod confirm_reset_recover;
|
pub mod confirm_reset_recover;
|
||||||
@ -15,6 +16,7 @@ pub mod warning_hi_prio;
|
|||||||
pub use confirm_action::{new_confirm_action, new_confirm_action_simple};
|
pub use confirm_action::{new_confirm_action, new_confirm_action_simple};
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
pub use confirm_firmware_update::new_confirm_firmware_update;
|
||||||
pub use confirm_output::new_confirm_output;
|
pub use confirm_output::new_confirm_output;
|
||||||
pub use confirm_reset_create::ConfirmResetCreate;
|
pub use confirm_reset_create::ConfirmResetCreate;
|
||||||
pub use confirm_reset_recover::ConfirmResetRecover;
|
pub use confirm_reset_recover::ConfirmResetRecover;
|
||||||
|
@ -42,7 +42,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
TextStyle,
|
TextStyle,
|
||||||
},
|
},
|
||||||
Border, CachedJpeg, Component, FormattedText, Label, Never, SwipeDirection, Timeout,
|
Border, CachedJpeg, Component, FormattedText, Never, SwipeDirection, Timeout,
|
||||||
},
|
},
|
||||||
flow::Swipable,
|
flow::Swipable,
|
||||||
geometry,
|
geometry,
|
||||||
@ -266,15 +266,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentMsgObj for super::component::bl_confirm::Confirm<'_> {
|
|
||||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
|
||||||
match msg {
|
|
||||||
super::component::bl_confirm::ConfirmMsg::Cancel => Ok(CANCELLED.as_obj()),
|
|
||||||
super::component::bl_confirm::ConfirmMsg::Confirm => Ok(CONFIRMED.as_obj()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||||
@ -1250,36 +1241,6 @@ pub extern "C" fn upy_check_homescreen_format(data: Obj) -> Obj {
|
|||||||
unsafe { util::try_or_raise(block) }
|
unsafe { util::try_or_raise(block) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" fn new_confirm_firmware_update(
|
|
||||||
n_args: usize,
|
|
||||||
args: *const Obj,
|
|
||||||
kwargs: *mut Map,
|
|
||||||
) -> Obj {
|
|
||||||
use super::component::bl_confirm::{Confirm, ConfirmTitle};
|
|
||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
|
||||||
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
|
||||||
let fingerprint: TString = kwargs.get(Qstr::MP_QSTR_fingerprint)?.try_into()?;
|
|
||||||
|
|
||||||
let title_str = TR::firmware_update__title.into();
|
|
||||||
let title = Label::left_aligned(title_str, theme::TEXT_BOLD).vertically_centered();
|
|
||||||
let msg = Label::left_aligned(description, theme::TEXT_NORMAL);
|
|
||||||
|
|
||||||
let left = Button::with_text(TR::buttons__cancel.into()).styled(theme::button_default());
|
|
||||||
let right = Button::with_text(TR::buttons__install.into()).styled(theme::button_confirm());
|
|
||||||
|
|
||||||
let obj = LayoutObj::new(
|
|
||||||
Confirm::new(theme::BG, left, right, ConfirmTitle::Text(title), msg).with_info(
|
|
||||||
TR::firmware_update__title_fingerprint.into(),
|
|
||||||
fingerprint,
|
|
||||||
theme::button_default(),
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
Ok(obj.into())
|
|
||||||
};
|
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn new_show_wait_text(message: Obj) -> Obj {
|
extern "C" fn new_show_wait_text(message: Obj) -> Obj {
|
||||||
let block = || {
|
let block = || {
|
||||||
let message: TString<'static> = message.try_into()?;
|
let message: TString<'static> = message.try_into()?;
|
||||||
@ -1811,8 +1772,8 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// description: str,
|
/// description: str,
|
||||||
/// fingerprint: str,
|
/// fingerprint: str,
|
||||||
/// ) -> LayoutObj[UiResult]:
|
/// ) -> LayoutObj[UiResult]:
|
||||||
/// """Ask whether to update firmware, optionally show fingerprint. Shared with bootloader."""
|
/// """Ask whether to update firmware, optionally show fingerprint."""
|
||||||
Qstr::MP_QSTR_confirm_firmware_update => obj_fn_kw!(0, new_confirm_firmware_update).as_obj(),
|
Qstr::MP_QSTR_confirm_firmware_update => obj_fn_kw!(0, flow::confirm_firmware_update::new_confirm_firmware_update).as_obj(),
|
||||||
|
|
||||||
/// def tutorial() -> LayoutObj[UiResult]:
|
/// def tutorial() -> LayoutObj[UiResult]:
|
||||||
/// """Show user how to interact with the device."""
|
/// """Show user how to interact with the device."""
|
||||||
|
@ -2044,7 +2044,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// *,
|
/// *,
|
||||||
/// description: str,
|
/// description: str,
|
||||||
/// fingerprint: str,
|
/// fingerprint: str,
|
||||||
/// ) -> None:
|
/// ) -> LayoutObj[UiResult]:
|
||||||
/// """Ask whether to update firmware, optionally show fingerprint. Shared with bootloader."""
|
/// """Ask whether to update firmware, optionally show fingerprint. Shared with bootloader."""
|
||||||
Qstr::MP_QSTR_confirm_firmware_update => obj_fn_kw!(0, new_confirm_firmware_update).as_obj(),
|
Qstr::MP_QSTR_confirm_firmware_update => obj_fn_kw!(0, new_confirm_firmware_update).as_obj(),
|
||||||
|
|
||||||
|
@ -538,7 +538,7 @@ def confirm_firmware_update(
|
|||||||
description: str,
|
description: str,
|
||||||
fingerprint: str,
|
fingerprint: str,
|
||||||
) -> LayoutObj[UiResult]:
|
) -> LayoutObj[UiResult]:
|
||||||
"""Ask whether to update firmware, optionally show fingerprint. Shared with bootloader."""
|
"""Ask whether to update firmware, optionally show fingerprint."""
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_mercury/layout.rs
|
# rust/src/ui/model_mercury/layout.rs
|
||||||
@ -1079,7 +1079,7 @@ def confirm_firmware_update(
|
|||||||
*,
|
*,
|
||||||
description: str,
|
description: str,
|
||||||
fingerprint: str,
|
fingerprint: str,
|
||||||
) -> None:
|
) -> LayoutObj[UiResult]:
|
||||||
"""Ask whether to update firmware, optionally show fingerprint. Shared with bootloader."""
|
"""Ask whether to update firmware, optionally show fingerprint. Shared with bootloader."""
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user