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

fix(core/ui): T2T1: display coinjoin icon on lockscreen

[no changelog]
This commit is contained in:
Martin Milata 2023-10-18 19:19:32 +02:00
parent 9a36b1f880
commit 9e33eb3e48
14 changed files with 67 additions and 22 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

View File

@ -37,6 +37,7 @@ static void _librust_qstrs(void) {
MP_QSTR_cancel_arrow;
MP_QSTR_case_sensitive;
MP_QSTR_chunkify;
MP_QSTR_coinjoin_authorized;
MP_QSTR_confirm_action;
MP_QSTR_confirm_address;
MP_QSTR_confirm_backup;

View File

@ -27,6 +27,7 @@ const NOTIFICATION_HEIGHT: i16 = 12;
const LABEL_OUTSET: i16 = 3;
const NOTIFICATION_FONT: Font = Font::NORMAL;
const NOTIFICATION_ICON: Icon = theme::ICON_WARNING;
const COINJOIN_CORNER: Point = AREA.top_right().ofs(Offset::new(-2, 2));
fn paint_default_image() {
theme::ICON_LOGO.draw(
@ -171,13 +172,15 @@ where
instruction: Child<Label<T>>,
/// Used for unlocking the device from lockscreen
invisible_buttons: Child<ButtonController<T>>,
/// Display coinjoin icon?
coinjoin_icon: Option<Icon>,
}
impl<T> Lockscreen<T>
where
T: StringType + Clone,
{
pub fn new(label: T, bootscreen: bool) -> Self {
pub fn new(label: T, bootscreen: bool, coinjoin_authorized: bool) -> Self {
// Buttons will not be visible, we only need all three of them to be present,
// so that even middle-click triggers the event.
let invisible_btn_layout = ButtonLayout::arrow_armed_arrow("".into());
@ -190,6 +193,7 @@ where
label: Child::new(Label::centered(label, theme::TEXT_BIG)),
instruction: Child::new(Label::centered(instruction_str.into(), theme::TEXT_NORMAL)),
invisible_buttons: Child::new(ButtonController::new(invisible_btn_layout)),
coinjoin_icon: coinjoin_authorized.then_some(theme::ICON_COINJOIN),
}
}
}
@ -223,6 +227,14 @@ where
);
self.instruction.paint();
self.label.paint();
if let Some(i) = &self.coinjoin_icon {
i.draw(
COINJOIN_CORNER,
Alignment2D::TOP_RIGHT,
theme::FG,
theme::BG,
)
}
}
}

View File

@ -1587,9 +1587,10 @@ extern "C" fn new_show_lockscreen(n_args: usize, args: *const Obj, kwargs: *mut
.try_into_option()?
.unwrap_or_else(|| model::FULL_NAME.into());
let bootscreen: bool = kwargs.get(Qstr::MP_QSTR_bootscreen)?.try_into()?;
let coinjoin_authorized: bool = kwargs.get_or(Qstr::MP_QSTR_coinjoin_authorized, false)?;
let skip_first_paint: bool = kwargs.get(Qstr::MP_QSTR_skip_first_paint)?.try_into()?;
let obj = LayoutObj::new(Lockscreen::new(label, bootscreen))?;
let obj = LayoutObj::new(Lockscreen::new(label, bootscreen, coinjoin_authorized))?;
if skip_first_paint {
obj.skip_first_paint();
}
@ -2008,6 +2009,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// label: str | None,
/// bootscreen: bool,
/// skip_first_paint: bool,
/// coinjoin_authorized: bool = False,
/// ) -> CANCELLED:
/// """Homescreen for locked device."""
Qstr::MP_QSTR_show_lockscreen => obj_fn_kw!(0, new_show_lockscreen).as_obj(),

Binary file not shown.

View File

@ -80,6 +80,7 @@ include_icon!(
"model_tr/res/cancel.toif",
empty_right_col = true
); // 7*7
include_icon!(ICON_COINJOIN, "model_tr/res/coinjoin.toif"); // 12*12
include_icon!(
ICON_DELETE,
"model_tr/res/delete.toif",

View File

@ -36,6 +36,7 @@ const LABEL_Y: i16 = HEIGHT - 18;
const LOCKED_Y: i16 = HEIGHT / 2 - 13;
const TAP_Y: i16 = HEIGHT / 2 + 14;
const HOLD_Y: i16 = 35;
const COINJOIN_Y: i16 = 30;
const LOADER_OFFSET: Offset = Offset::y(-10);
const LOADER_DELAY: Duration = Duration::from_millis(500);
const LOADER_DURATION: Duration = Duration::from_millis(2000);
@ -198,7 +199,7 @@ where
let text = HomescreenText {
text: self.label.as_ref(),
style: label_style,
offset: Offset::new(10, LABEL_Y),
offset: Offset::y(LABEL_Y),
icon: None,
};
@ -266,11 +267,16 @@ impl<T: AsRef<str>> crate::trace::Trace for Homescreen<T> {
pub struct Lockscreen<T> {
label: T,
bootscreen: bool,
coinjoin_authorized: bool,
}
impl<T> Lockscreen<T> {
pub fn new(label: T, bootscreen: bool) -> Self {
Lockscreen { label, bootscreen }
pub fn new(label: T, bootscreen: bool, coinjoin_authorized: bool) -> Self {
Lockscreen {
label,
bootscreen,
coinjoin_authorized,
}
}
}
@ -301,27 +307,37 @@ where
let mut label_style = theme::TEXT_DEMIBOLD;
label_style.text_color = theme::GREY_LIGHT;
let texts: [HomescreenText; 3] = [
let mut texts: &[HomescreenText] = &[
HomescreenText {
text: "",
style: theme::TEXT_NORMAL,
offset: Offset::new(2, COINJOIN_Y),
icon: Some(theme::ICON_COINJOIN),
},
HomescreenText {
text: locked,
style: theme::TEXT_BOLD,
offset: Offset::new(10, LOCKED_Y),
offset: Offset::y(LOCKED_Y),
icon: Some(theme::ICON_LOCK),
},
HomescreenText {
text: tap,
style: theme::TEXT_NORMAL,
offset: Offset::new(10, TAP_Y),
offset: Offset::y(TAP_Y),
icon: None,
},
HomescreenText {
text: self.label.as_ref(),
style: label_style,
offset: Offset::new(10, LABEL_Y),
offset: Offset::y(LABEL_Y),
icon: None,
},
];
if !self.coinjoin_authorized {
texts = &texts[1..];
}
let res = get_user_custom_image();
let mut show_default = true;
@ -330,14 +346,14 @@ where
let mut input = BufferInput(data.as_ref());
let mut pool = BufferJpegWork::get_cleared();
let mut hs_img = HomescreenJpeg::new(&mut input, pool.buffer.as_mut_slice());
homescreen_blurred(&mut hs_img, &texts);
homescreen_blurred(&mut hs_img, texts);
show_default = false;
} else if is_image_toif(data.as_ref()) {
let input = unwrap!(Toif::new(data.as_ref()));
let mut window = [0; UZLIB_WINDOW_SIZE];
let mut hs_img =
HomescreenToif::new(input.decompression_context(Some(&mut window)));
homescreen_blurred(&mut hs_img, &texts);
homescreen_blurred(&mut hs_img, texts);
show_default = false;
}
}
@ -346,7 +362,7 @@ where
let mut input = BufferInput(IMAGE_HOMESCREEN);
let mut pool = BufferJpegWork::get_cleared();
let mut hs_img = HomescreenJpeg::new(&mut input, pool.buffer.as_mut_slice());
homescreen_blurred(&mut hs_img, &texts);
homescreen_blurred(&mut hs_img, texts);
}
}
}

View File

@ -230,9 +230,11 @@ fn homescreen_position_text(
let text_top = screen().y0 + text.offset.y - font_max_height + font_baseline;
let text_bottom = screen().y0 + text.offset.y + font_baseline;
let icon_left = screen().center().x - (text_width_clamped + icon_size.x + TEXT_ICON_SPACE) / 2;
let total_width = text_width_clamped + icon_size.x + TEXT_ICON_SPACE;
let icon_left = screen().center().x + text.offset.x - total_width / 2;
let text_left = icon_left + icon_size.x + TEXT_ICON_SPACE;
let text_right = screen().center().x + (text_width_clamped + icon_size.x + TEXT_ICON_SPACE) / 2;
let text_right = screen().center().x + text.offset.x + total_width / 2;
let text_area = Rect::new(
Point::new(text_left, text_top),

View File

@ -1557,9 +1557,10 @@ extern "C" fn new_show_lockscreen(n_args: usize, args: *const Obj, kwargs: *mut
.try_into_option()?
.unwrap_or_else(|| model::FULL_NAME.into());
let bootscreen: bool = kwargs.get(Qstr::MP_QSTR_bootscreen)?.try_into()?;
let coinjoin_authorized: bool = kwargs.get_or(Qstr::MP_QSTR_coinjoin_authorized, false)?;
let skip_first_paint: bool = kwargs.get(Qstr::MP_QSTR_skip_first_paint)?.try_into()?;
let obj = LayoutObj::new(Lockscreen::new(label, bootscreen))?;
let obj = LayoutObj::new(Lockscreen::new(label, bootscreen, coinjoin_authorized))?;
if skip_first_paint {
obj.skip_first_paint();
}
@ -1988,6 +1989,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// label: str | None,
/// bootscreen: bool,
/// skip_first_paint: bool,
/// coinjoin_authorized: bool = False,
/// ) -> CANCELLED:
/// """Homescreen for locked device."""
Qstr::MP_QSTR_show_lockscreen => obj_fn_kw!(0, new_show_lockscreen).as_obj(),

View File

@ -433,6 +433,7 @@ def show_lockscreen(
label: str | None,
bootscreen: bool,
skip_first_paint: bool,
coinjoin_authorized: bool = False,
) -> CANCELLED:
"""Homescreen for locked device."""
@ -883,6 +884,7 @@ def show_lockscreen(
label: str | None,
bootscreen: bool,
skip_first_paint: bool,
coinjoin_authorized: bool = False,
) -> CANCELLED:
"""Homescreen for locked device."""

View File

@ -51,7 +51,10 @@ async def lockscreen() -> None:
# Only show the lockscreen UI if the device can in fact be locked.
if can_lock_device():
await Lockscreen(label=storage.device.get_label())
await Lockscreen(
label=storage.device.get_label(),
coinjoin_authorized=is_set_any_session(MessageType.AuthorizeCoinJoin),
)
# Otherwise proceed directly to unlock() call. If the device is already unlocked,
# it should be a no-op storage-wise, but it resets the internal configuration
# to an unlocked state.

View File

@ -80,6 +80,7 @@ class Lockscreen(HomescreenBase):
self,
label: str | None,
bootscreen: bool = False,
coinjoin_authorized: bool = False,
) -> None:
self.bootscreen = bootscreen
skip = (
@ -90,6 +91,7 @@ class Lockscreen(HomescreenBase):
label=label,
bootscreen=bootscreen,
skip_first_paint=skip,
coinjoin_authorized=coinjoin_authorized,
),
)

View File

@ -92,6 +92,7 @@ class Lockscreen(HomescreenBase):
self,
label: str | None,
bootscreen: bool = False,
coinjoin_authorized: bool = False,
) -> None:
self.bootscreen = bootscreen
if bootscreen:
@ -105,6 +106,7 @@ class Lockscreen(HomescreenBase):
label=label,
bootscreen=bootscreen,
skip_first_paint=skip,
coinjoin_authorized=coinjoin_authorized,
),
)

View File

@ -737,7 +737,7 @@
},
"TR": {
"click_tests": {
"TR_test_autolock.py::test_autolock_does_not_interrupt_preauthorized": "b96ab80af28b6d5e13ef32a8cc19812445c6258a2ad64f15870c7490a37edc06",
"TR_test_autolock.py::test_autolock_does_not_interrupt_preauthorized": "22f65f6d9edc7659e5c54bdda6bd38c68c96637d2eb1f8475a536c9f49423b30",
"TR_test_autolock.py::test_autolock_does_not_interrupt_signing": "3d0833002f39256a15ee5008af9d2cd304c61bc2932cb6dc844c027bfed3ed1d",
"TR_test_autolock.py::test_autolock_interrupts_passphrase": "1ab8da65492ade3e6301f784b818d355959c665ea4b91e38f6dd2de8c8b21c84",
"TR_test_autolock.py::test_autolock_interrupts_signing": "5f26a18a711ec7d17c035cc60478249281edeeac512d4561e55bd7a3c2d2ef94",
@ -795,8 +795,8 @@
"TR_bitcoin-test_authorize_coinjoin.py::test_get_address": "a96bebc82d5aff9c6a8583ddb354e6427689a3be4fddf082c3cd0e8722e54d46",
"TR_bitcoin-test_authorize_coinjoin.py::test_get_public_key": "4c2bba305bab30de2fcff0cec5ab1192f2e4d826d86f91f7172dfa624f5f3139",
"TR_bitcoin-test_authorize_coinjoin.py::test_multisession_authorization": "5f70b535406a6254113ed2a5f780ba98b8205abf6425eb7038d22395953aa560",
"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx[False]": "76fe57750f0bfbaa84aaa99f67329dc93e505d51521c2a2490d523996b403aa3",
"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx[True]": "76fe57750f0bfbaa84aaa99f67329dc93e505d51521c2a2490d523996b403aa3",
"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx[False]": "ebe4ac22942f10915507491103d1151b2416ffebfd6c3ca6f2b28be8b35d4262",
"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx[True]": "ebe4ac22942f10915507491103d1151b2416ffebfd6c3ca6f2b28be8b35d4262",
"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_large": "4f275de439c812363140d3839ebddd9243e2bb34d80d02a487361148b2bbab71",
"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "4cf48d6bb48a9efbff9e2949d657fde4dea7ae9e92f47cafdfcd11d7765d76b8",
"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "db453154c6d8318befea7230eb2a9639fece5bdfd83c62fbb7a1e9195b77ac1b",
@ -2017,7 +2017,7 @@
},
"TT": {
"click_tests": {
"TT_test_autolock.py::test_autolock_does_not_interrupt_preauthorized": "a46dce1eef3df4b242e90af5f6c6a1f2acdb27e7b56a1af0ab0982483bc0d9b7",
"TT_test_autolock.py::test_autolock_does_not_interrupt_preauthorized": "521b6ce07207c262b832fb4e78477f89211dc02a4b6e02a6fe8d389a2be909cf",
"TT_test_autolock.py::test_autolock_does_not_interrupt_signing": "e8ff223f44e97a98fbef62c2ed314bdc2d3a2f160d0396d09733847ce103494d",
"TT_test_autolock.py::test_autolock_interrupts_passphrase": "15ce8ca8c46be745296ad39b2df4e4503f1b3208c3f5b3e3f48d7bd172779605",
"TT_test_autolock.py::test_autolock_interrupts_signing": "a9b983a624b6ca20fd976fc59b570e0bfebc847a448a1db63717932d96cde15c",
@ -2078,8 +2078,8 @@
"TT_bitcoin-test_authorize_coinjoin.py::test_get_address": "f4de0499dac628067619c6081d4ebdba0ad196af7bf9662c5387386eba9e9729",
"TT_bitcoin-test_authorize_coinjoin.py::test_get_public_key": "38a7eac0cf0be45770fb28da9c2f74bac6404e85f2a3801acdd4b0107d99f2ff",
"TT_bitcoin-test_authorize_coinjoin.py::test_multisession_authorization": "d39b3290ddfecd5a3ceaf249543eaccb2b71c21eb2dbeabef94fe866ad7ce6a8",
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx[False]": "a5601b1f876c598cfe9361b4203a0b2908e860bef93d3fcc1a4fd2f89eeddfec",
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx[True]": "a5601b1f876c598cfe9361b4203a0b2908e860bef93d3fcc1a4fd2f89eeddfec",
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx[False]": "00f8d6cc8ad60877dc4629295e438f29912456f0767997ce3ba9277d1e1bbf22",
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx[True]": "00f8d6cc8ad60877dc4629295e438f29912456f0767997ce3ba9277d1e1bbf22",
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_large": "312fca890a6e93da6c3705e3b3c97ba38dd336374634dbed9134362420273380",
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "a0757616e39b5883ccfba01af3b386d1fc2d4a00517b2c3d79519ce0f60bc5cd",
"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "b8ca0b72adfb0cfa1ff653c83a0995517b71f8bfc217753e16aab49dd82a3a65",