1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-04 11:51:50 +00:00

refactor(core/rust/ui): erase button clears PIN after 2s

[no changelog]
This commit is contained in:
Martin Milata 2022-04-19 23:01:10 +02:00
parent e58736f746
commit 7b5c618576
2 changed files with 60 additions and 22 deletions

View File

@ -1,8 +1,11 @@
use crate::ui::{ use crate::{
component::{Component, ComponentExt, Event, EventCtx, GridPlaced, Map}, time::Duration,
display::{self, Color, Font}, ui::{
event::TouchEvent, component::{Component, ComponentExt, Event, EventCtx, GridPlaced, Map, TimerToken},
geometry::{Insets, Offset, Rect}, display::{self, Color, Font},
event::TouchEvent,
geometry::{Insets, Offset, Rect},
},
}; };
use super::theme; use super::theme;
@ -11,6 +14,7 @@ pub enum ButtonMsg {
Pressed, Pressed,
Released, Released,
Clicked, Clicked,
LongPressed,
} }
pub struct Button<T> { pub struct Button<T> {
@ -18,6 +22,8 @@ pub struct Button<T> {
content: ButtonContent<T>, content: ButtonContent<T>,
styles: ButtonStyleSheet, styles: ButtonStyleSheet,
state: State, state: State,
long_press: Option<Duration>,
long_timer: Option<TimerToken>,
} }
impl<T> Button<T> { impl<T> Button<T> {
@ -34,6 +40,8 @@ impl<T> Button<T> {
area: Rect::zero(), area: Rect::zero(),
styles: theme::button_default(), styles: theme::button_default(),
state: State::Initial, state: State::Initial,
long_press: None,
long_timer: None,
} }
} }
@ -54,6 +62,11 @@ impl<T> Button<T> {
self self
} }
pub fn with_long_press(mut self, duration: Duration) -> Self {
self.long_press = Some(duration);
self
}
pub fn enable_if(&mut self, ctx: &mut EventCtx, enabled: bool) { pub fn enable_if(&mut self, ctx: &mut EventCtx, enabled: bool) {
if enabled { if enabled {
self.enable(ctx); self.enable(ctx);
@ -210,6 +223,9 @@ where
// Touch started in our area, transform to `Pressed` state. // Touch started in our area, transform to `Pressed` state.
if self.area.contains(pos) { if self.area.contains(pos) {
self.set(ctx, State::Pressed); self.set(ctx, State::Pressed);
if let Some(duration) = self.long_press {
self.long_timer = Some(ctx.request_timer(duration));
}
return Some(ButtonMsg::Pressed); return Some(ButtonMsg::Pressed);
} }
} }
@ -245,6 +261,16 @@ where
_ => { _ => {
// Touch finished outside our area. // Touch finished outside our area.
self.set(ctx, State::Initial); self.set(ctx, State::Initial);
self.long_timer = None;
}
}
}
Event::Timer(token) => {
if self.long_timer == Some(token) {
self.long_timer = None;
if matches!(self.state, State::Pressed) {
self.set(ctx, State::Initial);
return Some(ButtonMsg::LongPressed);
} }
} }
} }

View File

@ -2,6 +2,7 @@ use core::{mem, ops::Deref};
use heapless::String; use heapless::String;
use crate::{ use crate::{
time::Duration,
trezorhal::random, trezorhal::random,
ui::{ ui::{
component::{ component::{
@ -9,13 +10,13 @@ use crate::{
Pad, Pad,
}, },
display, display,
event::TouchEvent,
geometry::{Alignment, Grid, Insets, Offset, Rect}, geometry::{Alignment, Grid, Insets, Offset, Rect},
model_tt::{ model_tt::{
component::{ component::{
button::{Button, ButtonContent, ButtonMsg::Clicked}, button::{Button, ButtonContent, ButtonMsg, ButtonMsg::Clicked},
theme, theme,
}, },
event::TouchEvent,
}, },
}, },
}; };
@ -27,6 +28,7 @@ pub enum PinKeyboardMsg {
const MAX_LENGTH: usize = 9; const MAX_LENGTH: usize = 9;
const DIGIT_COUNT: usize = 10; // 0..10 const DIGIT_COUNT: usize = 10; // 0..10
const ERASE_HOLD_DURATION: Duration = Duration::from_secs(2);
const HEADER_HEIGHT: i32 = 25; const HEADER_HEIGHT: i32 = 25;
const HEADER_PADDING_SIDE: i32 = 5; const HEADER_PADDING_SIDE: i32 = 5;
@ -45,7 +47,7 @@ pub struct PinKeyboard<T> {
minor_prompt: Label<T>, minor_prompt: Label<T>,
major_warning: Option<Label<T>>, major_warning: Option<Label<T>>,
textbox: Child<PinDots>, textbox: Child<PinDots>,
reset_btn: Child<Maybe<Button<&'static str>>>, erase_btn: Child<Maybe<Button<&'static str>>>,
cancel_btn: Child<Maybe<Button<&'static str>>>, cancel_btn: Child<Maybe<Button<&'static str>>>,
confirm_btn: Child<Button<&'static str>>, confirm_btn: Child<Button<&'static str>>,
digit_btns: [Child<Button<&'static str>>; DIGIT_COUNT], digit_btns: [Child<Button<&'static str>>; DIGIT_COUNT],
@ -66,10 +68,11 @@ where
allow_cancel: bool, allow_cancel: bool,
) -> Self { ) -> Self {
// Control buttons. // Control buttons.
let reset_btn = Button::with_icon(theme::ICON_BACK) let erase_btn = Button::with_icon(theme::ICON_BACK)
.styled(theme::button_reset()) .styled(theme::button_reset())
.with_long_press(ERASE_HOLD_DURATION)
.initially_enabled(false); .initially_enabled(false);
let reset_btn = Maybe::hidden(theme::BG, reset_btn).into_child(); let erase_btn = Maybe::hidden(theme::BG, erase_btn).into_child();
let cancel_btn = Button::with_icon(theme::ICON_CANCEL).styled(theme::button_cancel()); let cancel_btn = Button::with_icon(theme::ICON_CANCEL).styled(theme::button_cancel());
let cancel_btn = let cancel_btn =
@ -82,7 +85,7 @@ where
major_warning: major_warning major_warning: major_warning
.map(|text| Label::left_aligned(text, theme::label_keyboard_warning())), .map(|text| Label::left_aligned(text, theme::label_keyboard_warning())),
textbox: PinDots::new(theme::label_default()).into_child(), textbox: PinDots::new(theme::label_default()).into_child(),
reset_btn, erase_btn,
cancel_btn, cancel_btn,
confirm_btn: Button::with_icon(theme::ICON_CONFIRM) confirm_btn: Button::with_icon(theme::ICON_CONFIRM)
.styled(theme::button_confirm()) .styled(theme::button_confirm())
@ -109,7 +112,7 @@ where
for btn in &mut self.digit_btns { for btn in &mut self.digit_btns {
btn.mutate(ctx, |ctx, btn| btn.enable_if(ctx, !is_full)); btn.mutate(ctx, |ctx, btn| btn.enable_if(ctx, !is_full));
} }
self.reset_btn.mutate(ctx, |ctx, btn| { self.erase_btn.mutate(ctx, |ctx, btn| {
btn.show_if(ctx, !is_empty); btn.show_if(ctx, !is_empty);
btn.inner_mut().enable_if(ctx, !is_empty); btn.inner_mut().enable_if(ctx, !is_empty);
}); });
@ -133,7 +136,8 @@ where
type Msg = PinKeyboardMsg; type Msg = PinKeyboardMsg;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
// Ignore the top padding for now, we need it to reliably register textbox touch events. // Ignore the top padding for now, we need it to reliably register textbox touch
// events.
let borders_no_top = Insets { let borders_no_top = Insets {
top: 0, top: 0,
..theme::borders() ..theme::borders()
@ -156,9 +160,9 @@ where
self.major_warning.as_mut().map(|c| c.place(major_area)); self.major_warning.as_mut().map(|c| c.place(major_area));
// Control buttons. // Control buttons.
let reset_cancel_area = grid.row_col(3, 0); let erase_cancel_area = grid.row_col(3, 0);
self.reset_btn.place(reset_cancel_area); self.erase_btn.place(erase_cancel_area);
self.cancel_btn.place(reset_cancel_area); self.cancel_btn.place(erase_cancel_area);
self.confirm_btn.place(grid.row_col(3, 2)); self.confirm_btn.place(grid.row_col(3, 2));
// Digit buttons. // Digit buttons.
@ -184,10 +188,18 @@ where
if let Some(Clicked) = self.cancel_btn.event(ctx, event) { if let Some(Clicked) = self.cancel_btn.event(ctx, event) {
return Some(PinKeyboardMsg::Cancelled); return Some(PinKeyboardMsg::Cancelled);
} }
if let Some(Clicked) = self.reset_btn.event(ctx, event) { match self.erase_btn.event(ctx, event) {
self.textbox.mutate(ctx, |ctx, t| t.clear(ctx)); Some(ButtonMsg::Clicked) => {
self.pin_modified(ctx); self.textbox.mutate(ctx, |ctx, t| t.pop(ctx));
return None; self.pin_modified(ctx);
return None;
}
Some(ButtonMsg::LongPressed) => {
self.textbox.mutate(ctx, |ctx, t| t.clear(ctx));
self.pin_modified(ctx);
return None;
}
_ => {}
} }
for btn in &mut self.digit_btns { for btn in &mut self.digit_btns {
if let Some(Clicked) = btn.event(ctx, event) { if let Some(Clicked) = btn.event(ctx, event) {
@ -202,7 +214,7 @@ where
} }
fn paint(&mut self) { fn paint(&mut self) {
self.reset_btn.paint(); self.erase_btn.paint();
if self.textbox.inner().is_empty() { if self.textbox.inner().is_empty() {
self.textbox.inner().clear_background(); self.textbox.inner().clear_background();
if let Some(ref mut w) = self.major_warning { if let Some(ref mut w) = self.major_warning {
@ -224,7 +236,7 @@ where
fn bounds(&self, sink: &mut dyn FnMut(Rect)) { fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
self.major_prompt.bounds(sink); self.major_prompt.bounds(sink);
self.minor_prompt.bounds(sink); self.minor_prompt.bounds(sink);
self.reset_btn.bounds(sink); self.erase_btn.bounds(sink);
self.cancel_btn.bounds(sink); self.cancel_btn.bounds(sink);
self.confirm_btn.bounds(sink); self.confirm_btn.bounds(sink);
self.textbox.bounds(sink); self.textbox.bounds(sink);