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

refactor(core): use PromptMsg instead of Option<>

PromptScreen now uses dedicated PromptMsg with Confirmed and Cancelled
values instead of empty Option<>. This change affects only mercury code.

This is more explicit and enables "yes" or "no" prompts screens.
Otherwise, the "no" option was handled by the 'x' button handled by
Frame.

[no changelog]
This commit is contained in:
obrusvit 2024-08-07 17:46:16 +02:00 committed by Vít Obrusník
parent 2b4d6eb798
commit 60ad7219fe
14 changed files with 150 additions and 62 deletions

View File

@ -76,7 +76,7 @@ pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
pub use number_input_slider::NumberInputSliderDialog;
pub use progress::Progress;
#[cfg(feature = "translations")]
pub use prompt_screen::PromptScreen;
pub use prompt_screen::{PromptMsg, PromptScreen};
pub use result::{ResultFooter, ResultScreen, ResultStyle};
pub use scroll::ScrollBar;
#[cfg(feature = "translations")]

View File

@ -1,18 +1,26 @@
use crate::ui::{
component::{Component, Event, EventCtx},
geometry::Rect,
model_mercury::theme,
shape::Renderer,
};
use super::{HoldToConfirm, TapToConfirm};
use super::{super::theme, BinarySelection, ButtonContent, HoldToConfirm, TapToConfirm};
/// Component requesting an action from a user. Most typically embedded as a
/// content of a Frame and promptin "Tap to confirm" or "Hold to XYZ".
/// content of a Frame. Options are:
/// - Tap to confirm
/// - Hold to confirm
/// - Yes/No selection
#[derive(Clone)]
pub enum PromptScreen {
Tap(TapToConfirm),
Hold(HoldToConfirm),
Choose(BinarySelection),
}
pub enum PromptMsg {
Confirmed,
Cancelled,
}
impl PromptScreen {
@ -53,23 +61,50 @@ impl PromptScreen {
theme::ICON_CHEVRON_RIGHT,
))
}
pub fn new_yes_or_no() -> Self {
PromptScreen::Choose(BinarySelection::new(
ButtonContent::Icon(theme::ICON_CLOSE),
ButtonContent::Icon(theme::ICON_SIMPLE_CHECKMARK30),
theme::button_cancel(),
theme::button_confirm(),
))
}
}
impl Component for PromptScreen {
type Msg = ();
type Msg = PromptMsg;
fn place(&mut self, bounds: Rect) -> Rect {
match self {
PromptScreen::Tap(t) => t.place(bounds),
PromptScreen::Hold(h) => h.place(bounds),
PromptScreen::Choose(c) => c.place(bounds),
}
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
match self {
PromptScreen::Tap(t) => t.event(ctx, event),
PromptScreen::Hold(h) => h.event(ctx, event),
PromptScreen::Tap(_) | PromptScreen::Hold(_) => {
let res = match self {
PromptScreen::Tap(t) => t.event(ctx, event),
PromptScreen::Hold(h) => h.event(ctx, event),
_ => None,
};
if res.is_some() {
return Some(PromptMsg::Confirmed);
}
}
PromptScreen::Choose(c) => {
if let Some(res) = c.event(ctx, event) {
match res {
super::BinarySelectionMsg::Left => return Some(PromptMsg::Cancelled),
super::BinarySelectionMsg::Right => return Some(PromptMsg::Confirmed),
}
}
}
}
None
}
fn paint(&mut self) {
@ -80,6 +115,7 @@ impl Component for PromptScreen {
match self {
PromptScreen::Tap(t) => t.render(target),
PromptScreen::Hold(h) => h.render(target),
PromptScreen::Choose(c) => c.render(target),
}
}
}
@ -90,7 +126,8 @@ impl crate::trace::Trace for PromptScreen {
t.component("PromptScreen");
match self {
PromptScreen::Tap(c) => t.child("TapToConfirm", c),
PromptScreen::Hold(c) => t.child("HoldToConfirm", c),
PromptScreen::Hold(h) => t.child("HoldToConfirm", h),
PromptScreen::Choose(c) => t.child("ChooseBinarySelection", c),
}
}
}

View File

@ -1,7 +1,3 @@
use super::super::{
component::{Frame, FrameMsg, PromptScreen, SwipeContent, VerticalMenu, VerticalMenuChoiceMsg},
theme,
};
use crate::{
error,
error::Error,
@ -23,6 +19,13 @@ use crate::{
},
};
use super::super::{
component::{
Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu, VerticalMenuChoiceMsg,
},
theme,
};
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ConfirmAction {
Intro,
@ -287,8 +290,9 @@ fn create_confirm(
}
let content_confirm = content_confirm.map(move |msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
flow.with_page(&ConfirmAction::Confirm, content_confirm)

View File

@ -19,7 +19,7 @@ use crate::{
use super::super::{
component::{
CancelInfoConfirmMsg, Frame, FrameMsg, PromptScreen, SwipeContent, VerticalMenu,
CancelInfoConfirmMsg, Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu,
VerticalMenuChoiceMsg,
},
theme,
@ -130,8 +130,9 @@ impl ConfirmFirmwareUpdate {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
let res = SwipeFlow::new(&ConfirmFirmwareUpdate::Intro)?

View File

@ -11,14 +11,14 @@ use crate::{
FlowMsg, FlowState, SwipeFlow,
},
layout::obj::LayoutObj,
model_mercury::component::SwipeContent,
},
};
use super::{
super::{
component::{
AddressDetails, Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg,
AddressDetails, Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu,
VerticalMenuChoiceMsg,
},
theme,
},
@ -139,8 +139,9 @@ impl ConfirmOutput {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
_ => None,
});
let res = SwipeFlow::new(&ConfirmOutput::Address)?

View File

@ -15,12 +15,13 @@ use crate::{
FlowMsg, FlowState, SwipeFlow,
},
layout::obj::LayoutObj,
model_mercury::component::{PromptScreen, SwipeContent},
},
};
use super::super::{
component::{Frame, FrameMsg, VerticalMenu, VerticalMenuChoiceMsg},
component::{
Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu, VerticalMenuChoiceMsg,
},
theme,
};
@ -155,8 +156,9 @@ fn new_confirm_reset_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Erro
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
})
.one_button_request(ButtonRequestCode::ResetDevice.with_name("confirm_setup_device"));

View File

@ -20,7 +20,8 @@ use crate::{
use super::super::{
component::{
CancelInfoConfirmMsg, Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg,
CancelInfoConfirmMsg, Frame, FrameMsg, PromptMsg, PromptScreen, VerticalMenu,
VerticalMenuChoiceMsg,
},
theme,
};
@ -128,7 +129,7 @@ impl SetNewPin {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
_ => None,
});

View File

@ -17,7 +17,9 @@ use crate::{
use super::{
super::{
component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg},
component::{
Frame, FrameMsg, PromptMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg,
},
theme,
},
util::ShowInfoParams,
@ -107,8 +109,9 @@ impl ConfirmSummary {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
// Menu
@ -151,8 +154,9 @@ impl ConfirmSummary {
.with_footer(TR::instructions__tap_to_confirm.into(), None)
.with_swipe(SwipeDirection::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
_ => None,
});
let res = SwipeFlow::new(&ConfirmSummary::Summary)?

View File

@ -16,12 +16,14 @@ use crate::{
FlowMsg, FlowState, SwipeFlow,
},
layout::obj::LayoutObj,
model_mercury::component::{CancelInfoConfirmMsg, PromptScreen, SwipeContent},
},
};
use super::super::{
component::{Frame, FrameMsg, VerticalMenu, VerticalMenuChoiceMsg},
component::{
CancelInfoConfirmMsg, Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu,
VerticalMenuChoiceMsg,
},
theme,
};
@ -206,7 +208,7 @@ impl ContinueRecoveryBeforeShares {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
_ => None,
});

View File

@ -15,14 +15,13 @@ use crate::{
FlowMsg, FlowState, SwipeFlow, SwipePage,
},
layout::{obj::LayoutObj, util::ConfirmBlob},
model_mercury::component::SwipeContent,
},
};
use super::super::{
component::{
AddressDetails, CancelInfoConfirmMsg, Frame, FrameMsg, PromptScreen, StatusScreen,
VerticalMenu, VerticalMenuChoiceMsg,
AddressDetails, CancelInfoConfirmMsg, Frame, FrameMsg, PromptMsg, PromptScreen,
StatusScreen, SwipeContent, VerticalMenu, VerticalMenuChoiceMsg,
},
theme,
};
@ -143,8 +142,9 @@ impl GetAddress {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
let content_confirmed = Frame::left_aligned(
@ -216,7 +216,7 @@ impl GetAddress {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
_ => None,
});

View File

@ -14,13 +14,13 @@ use crate::{
FlowMsg, FlowState, SwipeFlow,
},
layout::obj::LayoutObj,
model_mercury::component::SwipeContent,
},
};
use super::super::{
component::{
CancelInfoConfirmMsg, Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg,
CancelInfoConfirmMsg, Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu,
VerticalMenuChoiceMsg,
},
theme,
};
@ -132,7 +132,7 @@ impl PromptBackup {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
_ => None,
});

View File

@ -13,15 +13,15 @@ use crate::{
FlowState, SwipeFlow,
},
layout::obj::LayoutObj,
model_mercury::component::{
number_input_slider::{NumberInputSliderDialog, NumberInputSliderDialogMsg},
SwipeContent,
},
},
};
use super::super::{
component::{Frame, FrameMsg, PromptScreen, StatusScreen, VerticalMenu, VerticalMenuChoiceMsg},
component::{
number_input_slider::{NumberInputSliderDialog, NumberInputSliderDialogMsg},
Frame, FrameMsg, PromptMsg, PromptScreen, StatusScreen, SwipeContent, VerticalMenu,
VerticalMenuChoiceMsg,
},
theme,
};
@ -113,11 +113,12 @@ impl SetBrightness {
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
.with_swipe(SwipeDirection::Left, SwipeSettings::default())
.map(move |msg| match msg {
FrameMsg::Content(()) => {
FrameMsg::Content(PromptMsg::Confirmed) => {
let _ = storage::set_brightness(BRIGHTNESS.load(Ordering::Relaxed));
Some(FlowMsg::Confirmed)
}
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
let content_confirmed = Frame::left_aligned(

View File

@ -13,12 +13,13 @@ use crate::{
FlowMsg, FlowState, SwipeFlow,
},
layout::obj::LayoutObj,
model_mercury::component::SwipeContent,
},
};
use super::super::{
component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg},
component::{
Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu, VerticalMenuChoiceMsg,
},
theme,
};
@ -85,7 +86,9 @@ impl ShowTutorial {
SwipeContent::new(PromptScreen::new_tap_to_start()),
)
.with_footer(TR::instructions__tap_to_start.into(), None)
.map(|msg| matches!(msg, FrameMsg::Content(())).then_some(FlowMsg::Confirmed));
.map(|msg| {
matches!(msg, FrameMsg::Content(PromptMsg::Confirmed)).then_some(FlowMsg::Confirmed)
});
let content_step_begin = Frame::left_aligned(
TR::tutorial__title_lets_begin.into(),
@ -138,7 +141,9 @@ impl ShowTutorial {
SwipeContent::new(PromptScreen::new_hold_to_confirm()),
)
.with_footer(TR::instructions__hold_to_exit_tutorial.into(), None)
.map(|msg| matches!(msg, FrameMsg::Content(())).then_some(FlowMsg::Confirmed));
.map(|msg| {
matches!(msg, FrameMsg::Content(PromptMsg::Confirmed)).then_some(FlowMsg::Confirmed)
});
let content_step_done = Frame::left_aligned(
TR::tutorial__title_well_done.into(),
@ -182,7 +187,9 @@ impl ShowTutorial {
SwipeContent::new(PromptScreen::new_hold_to_confirm_danger()),
)
.with_footer(TR::instructions__hold_to_exit_tutorial.into(), None)
.map(|msg| matches!(msg, FrameMsg::Content(())).then_some(FlowMsg::Confirmed));
.map(|msg| {
matches!(msg, FrameMsg::Content(PromptMsg::Confirmed)).then_some(FlowMsg::Confirmed)
});
let res = SwipeFlow::new(&ShowTutorial::StepWelcome)?
.with_page(&ShowTutorial::StepWelcome, content_step_welcome)?

View File

@ -274,28 +274,56 @@ pub const fn button_warning_low() -> ButtonStyleSheet {
}
}
// TODO: delete
// TODO: somehow merge with button_passphrase_confirm?
pub const fn button_confirm() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {
font: Font::BOLD,
text_color: FG,
button_color: GREEN,
icon_color: GREY_LIGHT,
background_color: BG,
font: Font::DEMIBOLD,
text_color: GREEN_LIME,
button_color: GREEN_DARK,
icon_color: GREEN_LIME,
background_color: GREEN_DARK,
},
active: &ButtonStyle {
font: Font::BOLD,
text_color: FG,
button_color: GREEN_DARK,
icon_color: GREY_LIGHT,
font: Font::DEMIBOLD,
text_color: GREEN_LIME,
button_color: GREEN_LIGHT,
icon_color: GREEN_DARK,
background_color: GREEN_LIGHT,
},
// not used
disabled: &ButtonStyle {
font: Font::DEMIBOLD,
text_color: BG,
button_color: BG,
icon_color: BG,
background_color: BG,
},
}
}
pub const fn button_cancel() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {
font: Font::DEMIBOLD,
text_color: ORANGE_LIGHT,
button_color: ORANGE_DARK,
icon_color: ORANGE_LIGHT,
background_color: GREEN_DARK,
},
active: &ButtonStyle {
font: Font::DEMIBOLD,
text_color: ORANGE_DARK,
button_color: ORANGE_LIGHT,
icon_color: ORANGE_DARK,
background_color: ORANGE_LIGHT,
},
// not used
disabled: &ButtonStyle {
font: Font::BOLD,
text_color: GREY_LIGHT,
button_color: GREEN_DARK,
icon_color: GREY_LIGHT,
font: Font::DEMIBOLD,
text_color: BG,
button_color: BG,
icon_color: BG,
background_color: BG,
},
}