diff --git a/core/embed/rust/src/ui/model_mercury/component/mod.rs b/core/embed/rust/src/ui/model_mercury/component/mod.rs index abb63435e5..ca675a03a5 100644 --- a/core/embed/rust/src/ui/model_mercury/component/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/component/mod.rs @@ -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")] diff --git a/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs b/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs index 86a0840e38..214f603c48 100644 --- a/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs +++ b/core/embed/rust/src/ui/model_mercury/component/prompt_screen.rs @@ -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 { 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), } } } diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs index 9788a48a11..7450fbdfe5 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_action.rs @@ -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) diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_firmware_update.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_firmware_update.rs index f0e6e1182e..99a1b7c7fd 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_firmware_update.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_firmware_update.rs @@ -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)? diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs index 8ec5e35a39..26c30a081d 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs @@ -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)? diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs index e3ba7742b3..424eb31e8d 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs @@ -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 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")); diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_set_new_pin.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_set_new_pin.rs index 0ed39821da..87cd2546d7 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_set_new_pin.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_set_new_pin.rs @@ -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, }); diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_summary.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_summary.rs index 85988c048c..f128180e0f 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_summary.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_summary.rs @@ -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)? diff --git a/core/embed/rust/src/ui/model_mercury/flow/continue_recovery.rs b/core/embed/rust/src/ui/model_mercury/flow/continue_recovery.rs index 2988ee15a0..218dc50387 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/continue_recovery.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/continue_recovery.rs @@ -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, }); diff --git a/core/embed/rust/src/ui/model_mercury/flow/get_address.rs b/core/embed/rust/src/ui/model_mercury/flow/get_address.rs index 7eaede6f75..7033341e3c 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/get_address.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/get_address.rs @@ -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, }); diff --git a/core/embed/rust/src/ui/model_mercury/flow/prompt_backup.rs b/core/embed/rust/src/ui/model_mercury/flow/prompt_backup.rs index 899a0040b3..87d404d647 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/prompt_backup.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/prompt_backup.rs @@ -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, }); diff --git a/core/embed/rust/src/ui/model_mercury/flow/set_brightness.rs b/core/embed/rust/src/ui/model_mercury/flow/set_brightness.rs index 1e2e470dd0..d069e032f5 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/set_brightness.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/set_brightness.rs @@ -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( diff --git a/core/embed/rust/src/ui/model_mercury/flow/show_tutorial.rs b/core/embed/rust/src/ui/model_mercury/flow/show_tutorial.rs index 75f1f1f872..27d9d20fb0 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/show_tutorial.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/show_tutorial.rs @@ -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)? diff --git a/core/embed/rust/src/ui/model_mercury/theme/mod.rs b/core/embed/rust/src/ui/model_mercury/theme/mod.rs index c38a6f1ec6..0c8580f54a 100644 --- a/core/embed/rust/src/ui/model_mercury/theme/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/theme/mod.rs @@ -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, }, }