mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 15:38:11 +00:00
feat(core): confirm homescreen image with thumbnail
[no changelog]
This commit is contained in:
parent
d00e87ea80
commit
1359b21508
@ -20,6 +20,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_jpeg_info;
|
MP_QSTR_jpeg_info;
|
||||||
MP_QSTR_jpeg_test;
|
MP_QSTR_jpeg_test;
|
||||||
MP_QSTR_confirm_action;
|
MP_QSTR_confirm_action;
|
||||||
|
MP_QSTR_confirm_homescreen;
|
||||||
MP_QSTR_confirm_blob;
|
MP_QSTR_confirm_blob;
|
||||||
MP_QSTR_confirm_properties;
|
MP_QSTR_confirm_properties;
|
||||||
MP_QSTR_confirm_coinjoin;
|
MP_QSTR_confirm_coinjoin;
|
||||||
@ -99,6 +100,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_min_count;
|
MP_QSTR_min_count;
|
||||||
MP_QSTR_max_count;
|
MP_QSTR_max_count;
|
||||||
MP_QSTR_items;
|
MP_QSTR_items;
|
||||||
|
MP_QSTR_image;
|
||||||
MP_QSTR_active;
|
MP_QSTR_active;
|
||||||
MP_QSTR_info_button;
|
MP_QSTR_info_button;
|
||||||
MP_QSTR_time_ms;
|
MP_QSTR_time_ms;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#[cfg(feature = "jpeg")]
|
||||||
|
use crate::ui::geometry::Offset;
|
||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
component::{Component, Event, EventCtx, Never},
|
component::{Component, Event, EventCtx, Never},
|
||||||
display,
|
display,
|
||||||
@ -64,3 +66,14 @@ pub fn image_painter(image: &'static [u8]) -> Painter<impl FnMut(Rect)> {
|
|||||||
let f = move |area: Rect| display::image(area.center(), image);
|
let f = move |area: Rect| display::image(area.center(), image);
|
||||||
Painter::new(f)
|
Painter::new(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "jpeg")]
|
||||||
|
pub fn jpeg_painter<'a>(
|
||||||
|
image: impl Fn() -> &'a [u8],
|
||||||
|
size: Offset,
|
||||||
|
scale: u8,
|
||||||
|
) -> Painter<impl FnMut(Rect)> {
|
||||||
|
let off = Offset::new(size.x / (2 << scale), size.y / (2 << scale));
|
||||||
|
let f = move |area: Rect| display::tjpgd::jpeg(image(), area.center() - off, scale);
|
||||||
|
Painter::new(f)
|
||||||
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use core::{cmp::Ordering, convert::TryInto};
|
use core::{cmp::Ordering, convert::TryInto};
|
||||||
|
use cstr_core::cstr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
micropython::{
|
micropython::{
|
||||||
buffer::StrBuffer,
|
buffer::{get_buffer, StrBuffer},
|
||||||
gc::Gc,
|
gc::Gc,
|
||||||
iter::{Iter, IterBuf},
|
iter::{Iter, IterBuf},
|
||||||
list::List,
|
list::List,
|
||||||
@ -28,6 +29,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
Border, Component, Empty, Timeout, TimeoutMsg,
|
Border, Component, Empty, Timeout, TimeoutMsg,
|
||||||
},
|
},
|
||||||
|
display::tjpgd::jpeg_info,
|
||||||
geometry,
|
geometry,
|
||||||
layout::{
|
layout::{
|
||||||
obj::{ComponentMsgObj, LayoutObj},
|
obj::{ComponentMsgObj, LayoutObj},
|
||||||
@ -466,6 +468,37 @@ 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 size = match jpeg_info(buffer_func()) {
|
||||||
|
Some(info) => info.0,
|
||||||
|
_ => return Err(Error::ValueError(cstr!("Invalid image."))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let buttons = Button::cancel_confirm_text(None, "CONFIRM");
|
||||||
|
let obj = LayoutObj::new(
|
||||||
|
Frame::centered(
|
||||||
|
theme::label_title(),
|
||||||
|
title,
|
||||||
|
Dialog::new(painter::jpeg_painter(buffer_func, size, 1), buttons),
|
||||||
|
)
|
||||||
|
.with_border(theme::borders()),
|
||||||
|
)?;
|
||||||
|
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()?;
|
||||||
@ -1322,6 +1355,15 @@ 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,
|
||||||
|
@ -97,6 +97,15 @@ def confirm_action(
|
|||||||
"""Confirm action."""
|
"""Confirm action."""
|
||||||
|
|
||||||
|
|
||||||
|
# rust/src/ui/model_tt/layout.rs
|
||||||
|
def confirm_homescreen(
|
||||||
|
*,
|
||||||
|
title: str,
|
||||||
|
image: bytes,
|
||||||
|
) -> object:
|
||||||
|
"""Confirm homescreen."""
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_tt/layout.rs
|
# rust/src/ui/model_tt/layout.rs
|
||||||
def confirm_blob(
|
def confirm_blob(
|
||||||
*,
|
*,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor.enums import ButtonRequestType
|
from trezor.enums import ButtonRequestType
|
||||||
from trezor.ui.layouts import confirm_action
|
from trezor.ui.layouts import confirm_action, confirm_homescreen
|
||||||
from trezor.wire import DataError
|
from trezor.wire import DataError
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -73,7 +73,7 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
|
|||||||
|
|
||||||
if homescreen is not None:
|
if homescreen is not None:
|
||||||
_validate_homescreen(homescreen)
|
_validate_homescreen(homescreen)
|
||||||
await _require_confirm_change_homescreen(ctx)
|
await _require_confirm_change_homescreen(ctx, homescreen)
|
||||||
try:
|
try:
|
||||||
storage_device.set_homescreen(homescreen)
|
storage_device.set_homescreen(homescreen)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -122,14 +122,22 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
|
|||||||
return Success(message="Settings applied")
|
return Success(message="Settings applied")
|
||||||
|
|
||||||
|
|
||||||
async def _require_confirm_change_homescreen(ctx: GenericContext) -> None:
|
async def _require_confirm_change_homescreen(
|
||||||
await confirm_action(
|
ctx: GenericContext, homescreen: bytes
|
||||||
ctx,
|
) -> None:
|
||||||
"set_homescreen",
|
if homescreen == b"":
|
||||||
"Set homescreen",
|
await confirm_action(
|
||||||
description="Do you really want to change the homescreen image?",
|
ctx,
|
||||||
br_code=BRT_PROTECT_CALL,
|
"set_homescreen",
|
||||||
)
|
"Set homescreen",
|
||||||
|
description="Do you really want to set default homescreen image?",
|
||||||
|
br_code=BRT_PROTECT_CALL,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await confirm_homescreen(
|
||||||
|
ctx,
|
||||||
|
homescreen,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _require_confirm_change_label(ctx: GenericContext, label: str) -> None:
|
async def _require_confirm_change_label(ctx: GenericContext, label: str) -> None:
|
||||||
|
@ -334,6 +334,25 @@ async def confirm_path_warning(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_homescreen(
|
||||||
|
ctx: GenericContext,
|
||||||
|
image: bytes,
|
||||||
|
) -> None:
|
||||||
|
await raise_if_not_confirmed(
|
||||||
|
interact(
|
||||||
|
ctx,
|
||||||
|
RustLayout(
|
||||||
|
trezorui2.confirm_homescreen(
|
||||||
|
title="SET HOMESCREEN",
|
||||||
|
image=image,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"set_homesreen",
|
||||||
|
ButtonRequestType.ProtectCall,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _show_xpub(xpub: str, title: str, cancel: str | None) -> ui.Layout:
|
def _show_xpub(xpub: str, title: str, cancel: str | None) -> ui.Layout:
|
||||||
content = RustLayout(
|
content = RustLayout(
|
||||||
trezorui2.confirm_blob(
|
trezorui2.confirm_blob(
|
||||||
|
Loading…
Reference in New Issue
Block a user