1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 20:38:10 +00:00

feat(core): show new homescreen preview for T2B1

[no changelog]
This commit is contained in:
grdddj 2023-09-19 10:59:03 +02:00 committed by Jiří Musil
parent 1f7c78a4ed
commit 0c4540ae0a
6 changed files with 155 additions and 17 deletions

View File

@ -12,7 +12,7 @@ use crate::{
use super::{ use super::{
super::constant, common::display_center, theme, ButtonController, ButtonControllerMsg, super::constant, common::display_center, theme, ButtonController, ButtonControllerMsg,
ButtonLayout, ButtonLayout, ButtonPos, CancelConfirmMsg,
}; };
const AREA: Rect = constant::screen(); const AREA: Rect = constant::screen();
@ -220,6 +220,70 @@ where
} }
} }
pub struct ConfirmHomescreen<T, F>
where
T: StringType,
{
title: Child<Label<T>>,
buffer_func: F,
buttons: Child<ButtonController<T>>,
}
impl<T, F> ConfirmHomescreen<T, F>
where
T: StringType + Clone,
{
pub fn new(title: T, buffer_func: F) -> Self {
let btn_layout = ButtonLayout::cancel_none_text("CHANGE".into());
ConfirmHomescreen {
title: Child::new(Label::centered(title, theme::TEXT_BOLD)),
buffer_func,
buttons: Child::new(ButtonController::new(btn_layout)),
}
}
}
impl<'a, T, F> Component for ConfirmHomescreen<T, F>
where
T: StringType + Clone,
F: Fn() -> &'a [u8],
{
type Msg = CancelConfirmMsg;
fn place(&mut self, bounds: Rect) -> Rect {
let (title_content_area, button_area) = bounds.split_bottom(theme::BUTTON_HEIGHT);
let title_height = theme::TEXT_BOLD.text_font.line_height();
let (title_area, _) = title_content_area.split_top(title_height);
self.title.place(title_area);
self.buttons.place(button_area);
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
// Left button cancels, right confirms
if let Some(ButtonControllerMsg::Triggered(pos)) = self.buttons.event(ctx, event) {
match pos {
ButtonPos::Left => return Some(CancelConfirmMsg::Cancelled),
ButtonPos::Right => return Some(CancelConfirmMsg::Confirmed),
_ => {}
}
}
None
}
fn paint(&mut self) {
// Drawing the image full-screen first and then other things on top
let toif_data = unwrap!(Toif::new((self.buffer_func)()));
toif_data.draw(TOP_CENTER, Alignment2D::TOP_CENTER, theme::FG, theme::BG);
// Need to make all the title background black, so the title text is well
// visible
let title_area = self.title.inner().area();
rect_fill(title_area, theme::BG);
self.title.paint();
self.buttons.paint();
}
}
// DEBUG-ONLY SECTION BELOW // DEBUG-ONLY SECTION BELOW
#[cfg(feature = "ui_debug")] #[cfg(feature = "ui_debug")]
@ -243,3 +307,14 @@ where
t.child("label", &self.label); t.child("label", &self.label);
} }
} }
#[cfg(feature = "ui_debug")]
impl<T, F> crate::trace::Trace for ConfirmHomescreen<T, F>
where
T: StringType,
{
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("ConfirmHomescreen");
t.child("title", &self.title);
}
}

View File

@ -50,7 +50,7 @@ pub use flow::Flow;
pub use flow_pages::{FlowPages, Page}; pub use flow_pages::{FlowPages, Page};
pub use frame::{Frame, ScrollableContent, ScrollableFrame}; pub use frame::{Frame, ScrollableContent, ScrollableFrame};
#[cfg(feature = "micropython")] #[cfg(feature = "micropython")]
pub use homescreen::{Homescreen, Lockscreen}; pub use homescreen::{ConfirmHomescreen, Homescreen, Lockscreen};
pub use input_methods::{ pub use input_methods::{
number_input::NumberInput, number_input::NumberInput,
passphrase::PassphraseEntry, passphrase::PassphraseEntry,

View File

@ -6,8 +6,15 @@ use crate::{
error::Error, error::Error,
maybe_trace::MaybeTrace, maybe_trace::MaybeTrace,
micropython::{ micropython::{
buffer::StrBuffer, gc::Gc, iter::IterBuf, list::List, map::Map, module::Module, obj::Obj, buffer::{get_buffer, StrBuffer},
qstr::Qstr, util, gc::Gc,
iter::IterBuf,
list::List,
map::Map,
module::Module,
obj::Obj,
qstr::Qstr,
util,
}, },
strutil::StringType, strutil::StringType,
ui::{ ui::{
@ -38,9 +45,10 @@ use crate::{
use super::{ use super::{
component::{ component::{
AddressDetails, ButtonActions, ButtonDetails, ButtonLayout, ButtonPage, CancelConfirmMsg, AddressDetails, ButtonActions, ButtonDetails, ButtonLayout, ButtonPage, CancelConfirmMsg,
CancelInfoConfirmMsg, CoinJoinProgress, Flow, FlowPages, Frame, Homescreen, Lockscreen, CancelInfoConfirmMsg, CoinJoinProgress, ConfirmHomescreen, Flow, FlowPages, Frame,
NumberInput, Page, PassphraseEntry, PinEntry, Progress, ScrollableContent, ScrollableFrame, Homescreen, Lockscreen, NumberInput, Page, PassphraseEntry, PinEntry, Progress,
ShareWords, ShowMore, SimpleChoice, WelcomeScreen, WordlistEntry, WordlistType, ScrollableContent, ScrollableFrame, ShareWords, ShowMore, SimpleChoice, WelcomeScreen,
WordlistEntry, WordlistType,
}, },
constant, theme, constant, theme,
}; };
@ -242,6 +250,19 @@ where
} }
} }
impl<'a, T, F> ComponentMsgObj for ConfirmHomescreen<T, F>
where
T: StringType + Clone,
F: Fn() -> &'a [u8],
{
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
match msg {
CancelConfirmMsg::Confirmed => Ok(CONFIRMED.as_obj()),
CancelConfirmMsg::Cancelled => Ok(CANCELLED.as_obj()),
}
}
}
/// Function to create and call a `ButtonPage` dialog based on paginable content /// Function to create and call a `ButtonPage` dialog based on paginable content
/// (e.g. `Paragraphs` or `FormattedText`). /// (e.g. `Paragraphs` or `FormattedText`).
/// Has optional title (supply empty `StrBuffer` for that) and hold-to-confirm /// Has optional title (supply empty `StrBuffer` for that) and hold-to-confirm
@ -392,6 +413,24 @@ extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *m
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
} }
extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let data: Obj = kwargs.get(Qstr::MP_QSTR_image)?;
// Layout needs to hold the Obj to play nice with GC. Obj is resolved to &[u8]
// in every paint pass.
// SAFETY: We expect no existing mutable reference. Resulting reference is
// discarded before returning to micropython.
let buffer_func = move || unsafe { unwrap!(get_buffer(data)) };
let obj = LayoutObj::new(ConfirmHomescreen::new(title, buffer_func))?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { extern "C" fn new_confirm_reset_device(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: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
@ -1587,6 +1626,14 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// """Confirm action.""" /// """Confirm action."""
Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(), Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(),
/// def confirm_homescreen(
/// *,
/// title: str,
/// image: bytes,
/// ) -> object:
/// """Confirm homescreen."""
Qstr::MP_QSTR_confirm_homescreen => obj_fn_kw!(0, new_confirm_homescreen).as_obj(),
/// def confirm_blob( /// def confirm_blob(
/// *, /// *,
/// title: str, /// title: str,

View File

@ -29,6 +29,15 @@ def confirm_action(
"""Confirm action.""" """Confirm action."""
# rust/src/ui/model_tr/layout.rs
def confirm_homescreen(
*,
title: str,
image: bytes,
) -> object:
"""Confirm homescreen."""
# rust/src/ui/model_tr/layout.rs # rust/src/ui/model_tr/layout.rs
def confirm_blob( def confirm_blob(
*, *,

View File

@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
import trezorui2 import trezorui2
from trezor import utils from trezor import utils
from trezor.enums import ButtonRequestType from trezor.enums import ButtonRequestType
from trezor.ui.layouts import confirm_action, confirm_homescreen, confirm_single from trezor.ui.layouts import confirm_action
from trezor.wire import DataError from trezor.wire import DataError
if TYPE_CHECKING: if TYPE_CHECKING:
@ -151,6 +151,8 @@ async def apply_settings(msg: ApplySettings) -> Success:
async def _require_confirm_change_homescreen(homescreen: bytes) -> None: async def _require_confirm_change_homescreen(homescreen: bytes) -> None:
from trezor.ui.layouts import confirm_homescreen
if homescreen == b"": if homescreen == b"":
await confirm_action( await confirm_action(
"set_homescreen", "set_homescreen",
@ -159,12 +161,12 @@ async def _require_confirm_change_homescreen(homescreen: bytes) -> None:
br_code=BRT_PROTECT_CALL, br_code=BRT_PROTECT_CALL,
) )
else: else:
await confirm_homescreen( await confirm_homescreen(homescreen)
homescreen,
)
async def _require_confirm_change_label(label: str) -> None: async def _require_confirm_change_label(label: str) -> None:
from trezor.ui.layouts import confirm_single
await confirm_single( await confirm_single(
"set_label", "set_label",
"Device name", "Device name",

View File

@ -443,12 +443,17 @@ async def confirm_path_warning(
async def confirm_homescreen( async def confirm_homescreen(
image: bytes, image: bytes,
) -> None: ) -> None:
# TODO: show homescreen preview? await raise_if_not_confirmed(
await confirm_action( interact(
"set_homescreen", RustLayout(
"Set homescreen", trezorui2.confirm_homescreen(
description="Do you really want to set new homescreen image?", title="CHANGE HOMESCREEN?",
br_code=ButtonRequestType.ProtectCall, image=image,
)
),
"set_homesreen",
ButtonRequestType.ProtectCall,
)
) )