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:
parent
e58736f746
commit
7b5c618576
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user