Skip to content

Commit

Permalink
refactor(core/ui): new Mercury design for number input slider
Browse files Browse the repository at this point in the history
  • Loading branch information
ibz committed Jul 17, 2024
1 parent f8defd9 commit 3786874
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 82 deletions.
5 changes: 5 additions & 0 deletions core/embed/rust/librust_qstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ static void _librust_qstrs(void) {
MP_QSTR_bootscreen;
MP_QSTR_br_code;
MP_QSTR_br_type;
MP_QSTR_brightness__change_title;
MP_QSTR_brightness__changed_title;
MP_QSTR_brightness__title;
MP_QSTR_button;
MP_QSTR_button_event;
Expand Down Expand Up @@ -295,6 +297,7 @@ static void _librust_qstrs(void) {
MP_QSTR_instructions__learn_more;
MP_QSTR_instructions__shares_continue_with_x_template;
MP_QSTR_instructions__shares_start_with_1;
MP_QSTR_instructions__swipe_horizontally;
MP_QSTR_instructions__swipe_up;
MP_QSTR_instructions__tap_to_confirm;
MP_QSTR_instructions__tap_to_start;
Expand Down Expand Up @@ -618,6 +621,8 @@ static void _librust_qstrs(void) {
MP_QSTR_send__transaction_signed;
MP_QSTR_send__you_are_contributing;
MP_QSTR_set_brightness;
MP_QSTR_setting__adjust;
MP_QSTR_setting__apply;
MP_QSTR_share_words;
MP_QSTR_share_words__words_in_order;
MP_QSTR_share_words__wrote_down_all;
Expand Down
19 changes: 17 additions & 2 deletions core/embed/rust/src/translations/generated/translated_string.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

133 changes: 98 additions & 35 deletions core/embed/rust/src/ui/model_mercury/component/number_input_slider.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,48 @@
use crate::{
strutil::ShortString,
strutil::{ShortString, TString},
translations::TR,
ui::{
component::{base::ComponentExt, Child, Component, Event, EventCtx},
constant::screen,
display,
event::TouchEvent,
geometry::{Alignment, Insets, Point, Rect},
geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect},
shape::{self, Renderer},
},
};

use super::theme;
use super::{theme, Footer};

pub enum NumberInputSliderDialogMsg {
Changed(u16),
}

pub struct NumberInputSliderDialog {
area: Rect,
text_area: Rect,
input: Child<NumberInputSlider>,
init_footer: Footer<'static>,
modified_footer: Footer<'static>,
min: u16,
max: u16,
val: u16,
init_val: u16,
}

impl NumberInputSliderDialog {
pub fn new(min: u16, max: u16, init_value: u16) -> Self {
Self {
area: Rect::zero(),
text_area: Rect::zero(),
input: NumberInputSlider::new(min, max, init_value).into_child(),
init_footer: Footer::new::<TString<'static>>(
TR::instructions__swipe_horizontally.into(),
)
.with_description::<TString<'static>>(TR::setting__adjust.into()),
modified_footer: Footer::new::<TString<'static>>(TR::instructions__swipe_up.into())
.with_description::<TString<'static>>(TR::setting__apply.into()),
min,
max,
val: init_value,
init_val: init_value,
}
}

Expand All @@ -42,19 +51,39 @@ impl NumberInputSliderDialog {
}
}

const INPUT_AREA_HEIGHT: i16 = 91;

impl Component for NumberInputSliderDialog {
type Msg = NumberInputSliderDialogMsg;

fn place(&mut self, bounds: Rect) -> Rect {
self.area = bounds;
let content_area = self.area.inset(Insets::top(2 * theme::BUTTON_SPACING));
let (_, content_area) = content_area.split_top(30);
let (input_area, _) = content_area.split_top(15);
let (text_area, _) = content_area.split_bottom(theme::BUTTON_HEIGHT);

self.text_area = text_area;
let whole_area = self.area.inset(Insets::bottom(theme::SPACING));
let init_footer_height = self.init_footer.height();
let modified_footer_height = self.modified_footer.height();
let max_height = if init_footer_height > modified_footer_height {
init_footer_height
} else {
modified_footer_height
};
let (remaining, footer_area) = whole_area.split_bottom(max_height);
self.init_footer.place(footer_area);
self.modified_footer.place(footer_area);
let content_area = remaining;

let used_area = content_area
.inset(Insets::sides(theme::SPACING))
.inset(Insets::bottom(theme::SPACING));

let input_area = Rect::snap(
used_area.center(),
Offset::new(used_area.width(), INPUT_AREA_HEIGHT),
Alignment2D::CENTER,
);

self.input.place(input_area.inset(Insets::sides(20)));

bounds
}

Expand All @@ -72,17 +101,11 @@ impl Component for NumberInputSliderDialog {

fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
self.input.render(target);

let mut str = ShortString::new();
let val_pct = (100 * (self.val - self.min)) / (self.max - self.min);

unwrap!(ufmt::uwrite!(str, "{} %", val_pct));

shape::Text::new(self.text_area.center(), &str)
.with_font(theme::TEXT_NORMAL.text_font)
.with_fg(theme::TEXT_NORMAL.text_color)
.with_align(Alignment::Center)
.render(target);
if self.val == self.init_val || self.input.inner().touching {
self.init_footer.render(target);
} else {
self.modified_footer.render(target);
};
}
}

Expand All @@ -97,9 +120,11 @@ impl crate::trace::Trace for NumberInputSliderDialog {
pub struct NumberInputSlider {
area: Rect,
touch_area: Rect,
text_area: Rect,
min: u16,
max: u16,
value: u16,
touching: bool,
}

impl NumberInputSlider {
Expand All @@ -108,13 +133,15 @@ impl NumberInputSlider {
Self {
area: Rect::zero(),
touch_area: Rect::zero(),
text_area: Rect::zero(),
min,
max,
value,
touching: false,
}
}

pub fn slider_eval(&mut self, pos: Point, ctx: &mut EventCtx) -> Option<u16> {
pub fn touch_eval(&mut self, pos: Point, ctx: &mut EventCtx) -> Option<u16> {
if self.touch_area.contains(pos) {
let filled = pos.x - self.area.x0;
let filled = filled.clamp(0, self.area.width());
Expand All @@ -136,16 +163,26 @@ impl Component for NumberInputSlider {

fn place(&mut self, bounds: Rect) -> Rect {
self.area = bounds;
self.touch_area = bounds.outset(Insets::new(40, 20, 40, 20)).clamp(screen());
self.touch_area = bounds.outset(Insets::new(0, 20, 0, 20)).clamp(screen());
bounds
}

fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
if let Event::Touch(touch_event) = event {
return match touch_event {
TouchEvent::TouchStart(pos) => self.slider_eval(pos, ctx),
TouchEvent::TouchMove(pos) => self.slider_eval(pos, ctx),
TouchEvent::TouchEnd(pos) => self.slider_eval(pos, ctx),
TouchEvent::TouchStart(pos) => {
if self.touch_area.contains(pos) {
self.touching = true;
ctx.request_paint();
}
self.touch_eval(pos, ctx)
}
TouchEvent::TouchMove(pos) => self.touch_eval(pos, ctx),
TouchEvent::TouchEnd(pos) => {
self.touching = false;
ctx.request_paint();
self.touch_eval(pos, ctx)
}
TouchEvent::TouchAbort => None,
};
}
Expand All @@ -160,25 +197,51 @@ impl Component for NumberInputSlider {
}

fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
let val_pct = (100 * (self.value - self.min)) / (self.max - self.min);
let (top_left_shape, top_right_shape, bot_left_shape, bot_right_shape) =
shape::CornerHighlight::from_rect(
self.area,
if self.touching {
theme::GREY_DARK
} else {
theme::WHITE
},
theme::BG,
);
top_left_shape.render(target);
top_right_shape.render(target);
bot_left_shape.render(target);
bot_right_shape.render(target);

shape::Bar::new(self.area)
.with_radius(2)
.with_thickness(2)
.with_bg(theme::BG)
.with_fg(theme::FG)
.render(target);
let val_pct = (100 * (self.value - self.min)) / (self.max - self.min);

let inner = self.area.inset(Insets::uniform(1));
let inner = self.area.inset(Insets::uniform(10));

let fill_to = (val_pct as i16 * inner.width()) / 100;

let inner = inner.with_width(fill_to as _);

shape::Bar::new(inner)
.with_radius(1)
.with_bg(theme::FG)
.with_bg(if self.touching {
theme::WHITE
} else {
theme::GREY_EXTRA_DARK
})
.render(target);

let mut str = ShortString::new();
let val_pct = (100 * (self.value - self.min)) / (self.max - self.min);

unwrap!(ufmt::uwrite!(str, "{} %", val_pct));

if !self.touching {
let text_height = theme::TEXT_BOLD.text_font.line_height();
shape::Text::new(self.area.center() + Offset::new(0, text_height / 2), &str)
.with_font(theme::TEXT_BOLD.text_font)
.with_fg(theme::TEXT_BOLD.text_color)
.with_align(Alignment::Center)
.render(target);
}
}
}

Expand Down
Loading

0 comments on commit 3786874

Please sign in to comment.