1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-19 12:58:13 +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:
obrusvit 2024-07-23 00:39:24 +02:00 committed by Vít Obrusník
parent 53799cdee8
commit f41176af02
6 changed files with 153 additions and 45 deletions

View File

@ -0,0 +1 @@
[T3T1] New UI of confirming interaction-less firmware update

View File

@ -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())
}
}

View File

@ -1,4 +1,5 @@
pub mod confirm_action;
pub mod confirm_firmware_update;
pub mod confirm_output;
pub mod confirm_reset_create;
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};
mod util;
pub use confirm_firmware_update::new_confirm_firmware_update;
pub use confirm_output::new_confirm_output;
pub use confirm_reset_create::ConfirmResetCreate;
pub use confirm_reset_recover::ConfirmResetRecover;

View File

@ -42,7 +42,7 @@ use crate::{
},
TextStyle,
},
Border, CachedJpeg, Component, FormattedText, Label, Never, SwipeDirection, Timeout,
Border, CachedJpeg, Component, FormattedText, Never, SwipeDirection, Timeout,
},
flow::Swipable,
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 {
let block = move |_args: &[Obj], kwargs: &Map| {
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) }
}
#[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 {
let block = || {
let message: TString<'static> = message.try_into()?;
@ -1811,8 +1772,8 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// description: str,
/// fingerprint: str,
/// ) -> LayoutObj[UiResult]:
/// """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(),
/// """Ask whether to update firmware, optionally show fingerprint."""
Qstr::MP_QSTR_confirm_firmware_update => obj_fn_kw!(0, flow::confirm_firmware_update::new_confirm_firmware_update).as_obj(),
/// def tutorial() -> LayoutObj[UiResult]:
/// """Show user how to interact with the device."""

View File

@ -2044,7 +2044,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// *,
/// description: str,
/// fingerprint: str,
/// ) -> None:
/// ) -> LayoutObj[UiResult]:
/// """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(),

View File

@ -538,7 +538,7 @@ def confirm_firmware_update(
description: str,
fingerprint: str,
) -> 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
@ -1079,7 +1079,7 @@ def confirm_firmware_update(
*,
description: str,
fingerprint: str,
) -> None:
) -> LayoutObj[UiResult]:
"""Ask whether to update firmware, optionally show fingerprint. Shared with bootloader."""