1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-29 01:28:10 +00:00

fix(core/ui): Model T style update

[no changelog]
This commit is contained in:
Martin Milata 2023-03-06 18:54:23 +01:00
parent 3623f966dc
commit 19a2ea21b6
115 changed files with 489 additions and 377 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

BIN
core/assets/bg-back52.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

BIN
core/assets/caret-up24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
core/assets/check16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

BIN
core/assets/check24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

BIN
core/assets/circle48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

BIN
core/assets/coinjoin16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

BIN
core/assets/fg-check48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

BIN
core/assets/fg-error48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

BIN
core/assets/fg-info48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

BIN
core/assets/fg-user48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

BIN
core/assets/info32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 182 B

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

BIN
core/assets/octagon48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

BIN
core/assets/warning16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

BIN
core/assets/x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

BIN
core/assets/x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

View File

@ -27,7 +27,7 @@
#define BUFFER_PIXELS DISPLAY_RESX #define BUFFER_PIXELS DISPLAY_RESX
#define TEXT_BUFFER_HEIGHT 32 #define TEXT_BUFFER_HEIGHT 36
#if TEXT_BUFFER_HEIGHT < FONT_MAX_HEIGHT #if TEXT_BUFFER_HEIGHT < FONT_MAX_HEIGHT
#error Text buffer height is too small, please adjust to match used fonts #error Text buffer height is too small, please adjust to match used fonts

View File

@ -149,7 +149,7 @@ void display_bar_radius(int x, int y, int w, int h, uint16_t c, uint16_t b,
void display_bar_radius_buffer(int x, int y, int w, int h, uint8_t r, void display_bar_radius_buffer(int x, int y, int w, int h, uint8_t r,
buffer_text_t *buffer) { buffer_text_t *buffer) {
if (h > 32) { if (h > TEXT_BUFFER_HEIGHT) {
return; return;
} }
if (r != 2 && r != 4 && r != 8 && r != 16) { if (r != 2 && r != 4 && r != 8 && r != 16) {

View File

@ -29,6 +29,7 @@
/// FONT_MONO: int # id of monospace font /// FONT_MONO: int # id of monospace font
/// FONT_NORMAL: int # id of normal-width font /// FONT_NORMAL: int # id of normal-width font
/// FONT_BOLD: int # id of bold-width font /// FONT_BOLD: int # id of bold-width font
/// FONT_DEMIBOLD: int # id of demibold font
/// TOIF_FULL_COLOR_BE: int # full color big endian TOI image /// TOIF_FULL_COLOR_BE: int # full color big endian TOI image
/// TOIF_FULL_COLOR_LE: int # full color little endian TOI image /// TOIF_FULL_COLOR_LE: int # full color little endian TOI image
/// TOIF_GRAYSCALE_EH: int # grayscale even high TOI image /// TOIF_GRAYSCALE_EH: int # grayscale even high TOI image
@ -621,6 +622,7 @@ STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(DISPLAY_RESY)}, {MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(DISPLAY_RESY)},
{MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_ROM_INT(FONT_NORMAL)}, {MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_ROM_INT(FONT_NORMAL)},
{MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_ROM_INT(FONT_BOLD)}, {MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_ROM_INT(FONT_BOLD)},
{MP_ROM_QSTR(MP_QSTR_FONT_DEMIBOLD), MP_ROM_INT(FONT_DEMIBOLD)},
{MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_ROM_INT(FONT_MONO)}, {MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_ROM_INT(FONT_MONO)},
{MP_ROM_QSTR(MP_QSTR_TOIF_FULL_COLOR_BE), MP_ROM_INT(TOIF_FULL_COLOR_BE)}, {MP_ROM_QSTR(MP_QSTR_TOIF_FULL_COLOR_BE), MP_ROM_INT(TOIF_FULL_COLOR_BE)},
{MP_ROM_QSTR(MP_QSTR_TOIF_FULL_COLOR_LE), MP_ROM_INT(TOIF_FULL_COLOR_LE)}, {MP_ROM_QSTR(MP_QSTR_TOIF_FULL_COLOR_LE), MP_ROM_INT(TOIF_FULL_COLOR_LE)},

View File

@ -26,7 +26,7 @@ pub use maybe::Maybe;
pub use pad::Pad; pub use pad::Pad;
pub use paginated::{AuxPageMsg, PageMsg, Paginate}; pub use paginated::{AuxPageMsg, PageMsg, Paginate};
pub use painter::Painter; pub use painter::Painter;
pub use placed::{FixedHeightBar, Floating, GridPlaced, VSplit}; pub use placed::{FixedHeightBar, Floating, GridPlaced, Split};
pub use qr_code::Qr; pub use qr_code::Qr;
pub use text::{ pub use text::{
formatted::FormattedText, formatted::FormattedText,

View File

@ -1,6 +1,6 @@
use crate::ui::{ use crate::ui::{
component::{Component, Event, EventCtx}, component::{Component, Event, EventCtx},
geometry::{Alignment, Alignment2D, Grid, GridCellSpan, Insets, Offset, Rect, TOP_RIGHT}, geometry::{Alignment, Alignment2D, Axis, Grid, GridCellSpan, Insets, Offset, Rect, TOP_RIGHT},
}; };
pub struct GridPlaced<T> { pub struct GridPlaced<T> {
@ -195,25 +195,35 @@ where
} }
} }
pub struct VSplit<T, U> { pub struct Split<T, U> {
first: T, first: T,
second: U, second: U,
width: i16, axis: Axis,
size: i16,
spacing: i16, spacing: i16,
} }
impl<T, U> VSplit<T, U> { impl<T, U> Split<T, U> {
pub const fn new(width: i16, spacing: i16, first: T, second: U) -> Self { pub const fn new(axis: Axis, size: i16, spacing: i16, first: T, second: U) -> Self {
Self { Self {
first, first,
second, second,
width, axis,
size,
spacing, spacing,
} }
} }
pub const fn vertical(size: i16, spacing: i16, first: T, second: U) -> Self {
Self::new(Axis::Vertical, size, spacing, first, second)
}
pub const fn horizontal(size: i16, spacing: i16, first: T, second: U) -> Self {
Self::new(Axis::Horizontal, size, spacing, first, second)
}
} }
impl<M, T, U> Component for VSplit<T, U> impl<M, T, U> Component for Split<T, U>
where where
T: Component<Msg = M>, T: Component<Msg = M>,
U: Component<Msg = M>, U: Component<Msg = M>,
@ -221,10 +231,26 @@ where
type Msg = M; type Msg = M;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
let (left, right) = bounds.split_left(self.width); let size = if self.size == 0 {
let right = right.inset(Insets::left(self.spacing)); (bounds.size().axis(self.axis.cross()) - self.spacing) / 2
self.first.place(left); } else {
self.second.place(right); self.size
};
let (first, second) = match self.axis {
Axis::Vertical if size > 0 => bounds.split_left(size),
Axis::Vertical => bounds.split_right(-size),
Axis::Horizontal if size > 0 => bounds.split_top(size),
Axis::Horizontal => bounds.split_bottom(-size),
};
let (first, second) = match self.axis {
Axis::Vertical if size > 0 => (first, second.inset(Insets::left(self.spacing))),
Axis::Vertical => (first.inset(Insets::right(self.spacing)), second),
Axis::Horizontal if size > 0 => (first, second.inset(Insets::top(self.spacing))),
Axis::Horizontal => (first.inset(Insets::bottom(self.spacing)), second),
};
self.first.place(first);
self.second.place(second);
bounds bounds
} }
@ -241,13 +267,13 @@ where
} }
#[cfg(feature = "ui_debug")] #[cfg(feature = "ui_debug")]
impl<T, U> crate::trace::Trace for VSplit<T, U> impl<T, U> crate::trace::Trace for Split<T, U>
where where
T: Component + crate::trace::Trace, T: Component + crate::trace::Trace,
U: Component + crate::trace::Trace, U: Component + crate::trace::Trace,
{ {
fn trace(&self, d: &mut dyn crate::trace::Tracer) { fn trace(&self, d: &mut dyn crate::trace::Tracer) {
d.open("VSplit"); d.open("Split");
d.field("first", &self.first); d.field("first", &self.first);
d.field("second", &self.second); d.field("second", &self.second);
d.close(); d.close();

View File

@ -56,8 +56,8 @@ pub const TITLE_AREA_START_Y: i16 = 8;
pub const BUTTON_AREA_START: i16 = 188; pub const BUTTON_AREA_START: i16 = 188;
// UI icons. // UI icons.
pub const ICON_CANCEL: &[u8] = include_res!("model_tt/res/cancel.toif"); pub const ICON_CANCEL: &[u8] = include_res!("model_tt/res/x24.toif");
pub const ICON_CONFIRM: &[u8] = include_res!("model_tt/res/confirm.toif"); pub const ICON_CONFIRM: &[u8] = include_res!("model_tt/res/check24.toif");
// BLD icons // BLD icons
pub const CLOSE: &[u8] = include_res!("model_tt/res/close.toif"); pub const CLOSE: &[u8] = include_res!("model_tt/res/close.toif");

View File

@ -15,24 +15,30 @@ use crate::{
use super::{theme, Frame}; use super::{theme, Frame};
const MAX_XPUBS: usize = 16;
pub struct AddressDetails<T> { pub struct AddressDetails<T> {
qr_code: Frame<Qr, T>, qr_code: Frame<Qr, T>,
details: Frame<Paragraphs<ParagraphVecShort<T>>, T>, details: Frame<Paragraphs<ParagraphVecShort<T>>, T>,
xpub_view: Frame<Paragraphs<Paragraph<T>>, T>, xpub_view: Frame<Paragraphs<Paragraph<T>>, T>,
xpubs: Vec<(T, T), 16>, xpubs: Vec<(T, T), MAX_XPUBS>,
xpub_page_count: Vec<u8, MAX_XPUBS>,
current_page: usize, current_page: usize,
} }
impl<T> AddressDetails<T> impl<T> AddressDetails<T>
where where
T: ParagraphStrType + From<&'static str>, T: ParagraphStrType,
{ {
pub fn new( pub fn new(
qr_address: T, qr_address: T,
case_sensitive: bool, case_sensitive: bool,
account: Option<T>, account: Option<T>,
path: Option<T>, path: Option<T>,
) -> Result<Self, Error> { ) -> Result<Self, Error>
where
T: From<&'static str>,
{
let mut para = ParagraphVecShort::new(); let mut para = ParagraphVecShort::new();
if let Some(a) = account { if let Some(a) = account {
para.add(Paragraph::new(&theme::TEXT_NORMAL, "Account:".into())); para.add(Paragraph::new(&theme::TEXT_NORMAL, "Account:".into()));
@ -61,10 +67,11 @@ where
xpub_view: Frame::left_aligned( xpub_view: Frame::left_aligned(
theme::label_title(), theme::label_title(),
" \n ".into(), " \n ".into(),
Paragraph::new(&theme::TEXT_XPUB, "".into()).into_paragraphs(), Paragraph::new(&theme::TEXT_MONO, "".into()).into_paragraphs(),
) )
.with_border(theme::borders_horizontal_scroll()), .with_border(theme::borders_horizontal_scroll()),
xpubs: Vec::new(), xpubs: Vec::new(),
xpub_page_count: Vec::new(),
current_page: 0, current_page: 0,
}; };
Ok(result) Ok(result)
@ -75,6 +82,41 @@ where
.push((title, xpub)) .push((title, xpub))
.map_err(|_| Error::OutOfRange) .map_err(|_| Error::OutOfRange)
} }
fn switch_xpub(&mut self, i: usize, page: usize) -> usize
where
T: Clone,
{
// Context is needed for updating child so that it can request repaint. In this
// case the parent component that handles paging always requests complete
// repaint after page change so we can use a dummy context here.
let mut dummy_ctx = EventCtx::new();
self.xpub_view
.update_title(&mut dummy_ctx, self.xpubs[i].0.clone());
self.xpub_view.update_content(&mut dummy_ctx, |p| {
p.inner_mut().update(self.xpubs[i].1.clone());
let npages = p.page_count();
p.change_page(page);
npages
})
}
fn lookup(&self, scrollbar_page: usize) -> (usize, usize) {
let mut xpub_index = 0;
let mut xpub_page = scrollbar_page;
for page_count in self.xpub_page_count.iter().map(|pc| {
let upc: usize = (*pc).into();
upc
}) {
if page_count <= xpub_page {
xpub_page -= page_count;
xpub_index += 1;
} else {
break;
}
}
(xpub_index, xpub_page)
}
} }
impl<T> Paginate for AddressDetails<T> impl<T> Paginate for AddressDetails<T>
@ -82,30 +124,23 @@ where
T: ParagraphStrType + Clone, T: ParagraphStrType + Clone,
{ {
fn page_count(&mut self) -> usize { fn page_count(&mut self) -> usize {
2 + self.xpubs.len() let total_xpub_pages: u8 = self.xpub_page_count.iter().copied().sum();
2usize.saturating_add(total_xpub_pages.into())
} }
fn change_page(&mut self, to_page: usize) { fn change_page(&mut self, to_page: usize) {
self.current_page = to_page; self.current_page = to_page;
if to_page > 1 { if to_page > 1 {
let i = to_page - 2; let i = to_page - 2;
// Context is needed for updating child so that it can request repaint. In this let (xpub_index, xpub_page) = self.lookup(i);
// case the parent component that handles paging always requests complete self.switch_xpub(xpub_index, xpub_page);
// repaint after page change so we can use a dummy context here.
let mut dummy_ctx = EventCtx::new();
self.xpub_view
.update_title(&mut dummy_ctx, self.xpubs[i].0.clone());
self.xpub_view.update_content(&mut dummy_ctx, |p| {
p.inner_mut().update(self.xpubs[i].1.clone());
p.change_page(0)
});
} }
} }
} }
impl<T> Component for AddressDetails<T> impl<T> Component for AddressDetails<T>
where where
T: ParagraphStrType, T: ParagraphStrType + Clone,
{ {
type Msg = Never; type Msg = Never;
@ -113,6 +148,13 @@ where
self.qr_code.place(bounds); self.qr_code.place(bounds);
self.details.place(bounds); self.details.place(bounds);
self.xpub_view.place(bounds); self.xpub_view.place(bounds);
self.xpub_page_count.clear();
for i in 0..self.xpubs.len() {
let npages = self.switch_xpub(i, 0) as u8;
unwrap!(self.xpub_page_count.push(npages));
}
bounds bounds
} }

View File

@ -2,8 +2,8 @@ use crate::{
time::Duration, time::Duration,
ui::{ ui::{
component::{ component::{
Component, ComponentExt, Event, EventCtx, FixedHeightBar, Floating, GridPlaced, Map, Component, ComponentExt, Event, EventCtx, FixedHeightBar, Floating, Map, Paginate,
Paginate, TimerToken, VSplit, Split, TimerToken,
}, },
display::{self, toif::Icon, Color, Font}, display::{self, toif::Icon, Color, Font},
event::TouchEvent, event::TouchEvent,
@ -33,7 +33,7 @@ pub struct Button<T> {
impl<T> Button<T> { impl<T> Button<T> {
/// Offsets the baseline of the button text either up (negative) or down /// Offsets the baseline of the button text either up (negative) or down
/// (positive). /// (positive).
pub const BASELINE_OFFSET: i16 = -3; pub const BASELINE_OFFSET: i16 = -2;
pub const fn new(content: ButtonContent<T>) -> Self { pub const fn new(content: ButtonContent<T>) -> Self {
Self { Self {
@ -63,16 +63,16 @@ impl<T> Button<T> {
Self::new(ButtonContent::IconBlend(bg, fg, fg_offset)) Self::new(ButtonContent::IconBlend(bg, fg, fg_offset))
} }
pub fn empty() -> Self { pub const fn empty() -> Self {
Self::new(ButtonContent::Empty) Self::new(ButtonContent::Empty)
} }
pub fn styled(mut self, styles: ButtonStyleSheet) -> Self { pub const fn styled(mut self, styles: ButtonStyleSheet) -> Self {
self.styles = styles; self.styles = styles;
self self
} }
pub fn with_expanded_touch_area(mut self, expand: Insets) -> Self { pub const fn with_expanded_touch_area(mut self, expand: Insets) -> Self {
self.touch_expand = Some(expand); self.touch_expand = Some(expand);
self self
} }
@ -377,7 +377,7 @@ impl<T> Button<T> {
pub fn cancel_confirm( pub fn cancel_confirm(
left: Button<T>, left: Button<T>,
right: Button<T>, right: Button<T>,
right_size_factor: usize, left_is_small: bool,
) -> CancelConfirm< ) -> CancelConfirm<
T, T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>, impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
@ -386,59 +386,13 @@ impl<T> Button<T> {
where where
T: AsRef<str>, T: AsRef<str>,
{ {
let columns = 1 + right_size_factor; let width = if left_is_small {
theme::button_bar(( theme::BUTTON_WIDTH
GridPlaced::new(left)
.with_grid(1, columns)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 0)
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Cancelled)
}),
GridPlaced::new(right)
.with_grid(1, columns)
.with_spacing(theme::BUTTON_SPACING)
.with_from_to((0, 1), (0, right_size_factor))
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
}),
))
}
pub fn cancel_confirm_text(
left: Option<T>,
right: T,
) -> CancelConfirm<
T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
>
where
T: AsRef<str>,
{
let (left, right_size_factor) = if let Some(verb) = left {
(Button::with_text(verb), 1)
} else { } else {
(Button::with_icon(Icon::new(theme::ICON_CANCEL)), 2) 0
}; };
let right = Button::with_text(right).styled(theme::button_confirm()); theme::button_bar(Split::vertical(
width,
Self::cancel_confirm(left, right, right_size_factor)
}
pub fn cancel_confirm_square(
left: Button<T>,
right: Button<T>,
) -> CancelConfirmSquare<
T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
>
where
T: AsRef<str>,
{
theme::button_bar(VSplit::new(
theme::BUTTON_HEIGHT,
theme::BUTTON_SPACING, theme::BUTTON_SPACING,
left.map(|msg| { left.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Cancelled) (matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Cancelled)
@ -449,6 +403,34 @@ impl<T> Button<T> {
)) ))
} }
pub fn cancel_confirm_text(
left: Option<T>,
right: Option<T>,
) -> CancelConfirm<
T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
>
where
T: AsRef<str>,
{
let left_is_small: bool;
let left = if let Some(verb) = left {
left_is_small = verb.as_ref().len() <= 4;
Button::with_text(verb)
} else {
left_is_small = right.is_some();
Button::with_icon(Icon::new(theme::ICON_CANCEL))
};
let right = if let Some(verb) = right {
Button::with_text(verb).styled(theme::button_confirm())
} else {
Button::with_icon(Icon::new(theme::ICON_CONFIRM)).styled(theme::button_confirm())
};
Self::cancel_confirm(left, right, left_is_small)
}
pub fn cancel_info_confirm( pub fn cancel_info_confirm(
confirm: T, confirm: T,
info: T, info: T,
@ -461,69 +443,29 @@ impl<T> Button<T> {
where where
T: AsRef<str>, T: AsRef<str>,
{ {
let right = Button::with_text(confirm).styled(theme::button_confirm()); let right = Button::with_text(confirm)
let top = Button::with_text(info); .styled(theme::button_confirm())
let left = Button::with_icon(Icon::new(theme::ICON_CANCEL)); .map(|msg| {
theme::button_bar_rows( (matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Confirmed)
2, });
( let top = Button::with_text(info)
GridPlaced::new(left) .styled(theme::button_moreinfo())
.with_grid(2, 3) .map(|msg| (matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Info));
.with_spacing(theme::BUTTON_SPACING) let left = Button::with_icon(Icon::new(theme::ICON_CANCEL)).map(|msg| {
.with_row_col(1, 0) (matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled)
.map(|msg| { });
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled) let total_height = theme::BUTTON_HEIGHT + theme::BUTTON_SPACING + theme::INFO_BUTTON_HEIGHT;
}), FixedHeightBar::bottom(
GridPlaced::new(top) Split::horizontal(
.with_grid(2, 3) theme::INFO_BUTTON_HEIGHT,
.with_spacing(theme::BUTTON_SPACING) theme::BUTTON_SPACING,
.with_from_to((0, 0), (0, 2)) top,
.map(|msg| { Split::vertical(theme::BUTTON_WIDTH, theme::BUTTON_SPACING, left, right),
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Info)
}),
GridPlaced::new(right)
.with_grid(2, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_from_to((1, 1), (1, 2))
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Confirmed)
}),
), ),
total_height,
) )
} }
pub fn abort_info_enter() -> CancelInfoConfirm<
&'static str,
impl Fn(ButtonMsg) -> Option<CancelInfoConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelInfoConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelInfoConfirmMsg>,
> {
let left = Button::with_text("ABORT").styled(theme::button_cancel());
let middle = Button::with_text("INFO");
let right = Button::with_text("ENTER").styled(theme::button_confirm());
theme::button_bar((
GridPlaced::new(left)
.with_grid(1, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 0)
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled)
}),
GridPlaced::new(middle)
.with_grid(1, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 1)
.map(|msg| (matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Info)),
GridPlaced::new(right)
.with_grid(1, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 2)
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Confirmed)
}),
))
}
pub fn select_word( pub fn select_word(
words: [T; 3], words: [T; 3],
) -> CancelInfoConfirm< ) -> CancelInfoConfirm<
@ -536,38 +478,41 @@ impl<T> Button<T> {
T: AsRef<str>, T: AsRef<str>,
{ {
let btn = move |i, word| { let btn = move |i, word| {
GridPlaced::new(Button::with_text(word)) Button::with_text(word)
.with_grid(3, 1) .styled(theme::button_pin())
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(i, 0)
.map(move |msg| { .map(move |msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| SelectWordMsg::Selected(i)) (matches!(msg, ButtonMsg::Clicked)).then(|| SelectWordMsg::Selected(i))
}) })
}; };
let [top, middle, bottom] = words; let [top, middle, bottom] = words;
theme::button_bar_rows(3, (btn(0, top), btn(1, middle), btn(2, bottom))) let total_height = 3 * theme::BUTTON_HEIGHT + 2 * theme::BUTTON_SPACING;
FixedHeightBar::bottom(
Split::horizontal(
theme::BUTTON_HEIGHT,
theme::BUTTON_SPACING,
btn(0, top),
Split::horizontal(
theme::BUTTON_HEIGHT,
theme::BUTTON_SPACING,
btn(1, middle),
btn(2, bottom),
),
),
total_height,
)
} }
} }
type CancelConfirm<T, F0, F1> = FixedHeightBar<(
Map<GridPlaced<Button<T>>, F0>,
Map<GridPlaced<Button<T>>, F1>,
)>;
pub enum CancelConfirmMsg { pub enum CancelConfirmMsg {
Cancelled, Cancelled,
Confirmed, Confirmed,
} }
type CancelInfoConfirm<T, F0, F1, F2> = FixedHeightBar<( type CancelInfoConfirm<T, F0, F1, F2> =
Map<GridPlaced<Button<T>>, F0>, FixedHeightBar<Split<Map<Button<T>, F0>, Split<Map<Button<T>, F1>, Map<Button<T>, F2>>>>;
Map<GridPlaced<Button<T>>, F1>,
Map<GridPlaced<Button<T>>, F2>,
)>;
type CancelConfirmSquare<T, F0, F1> = type CancelConfirm<T, F0, F1> = FixedHeightBar<Split<Map<Button<T>, F0>, Map<Button<T>, F1>>>;
FixedHeightBar<VSplit<Map<Button<T>, F0>, Map<Button<T>, F1>>>;
pub enum CancelInfoConfirmMsg { pub enum CancelInfoConfirmMsg {
Cancelled, Cancelled,
@ -658,7 +603,9 @@ where
button: Floating::top_right( button: Floating::top_right(
theme::CORNER_BUTTON_SIDE, theme::CORNER_BUTTON_SIDE,
theme::CORNER_BUTTON_SPACING, theme::CORNER_BUTTON_SPACING,
Button::with_icon(icon), Button::with_icon(icon)
.with_expanded_touch_area(Insets::uniform(theme::CORNER_BUTTON_SPACING))
.styled(theme::button_moreinfo()),
), ),
} }
} }

View File

@ -60,8 +60,8 @@ where
page_swipe.allow_left = scrollbar.has_next_page(); page_swipe.allow_left = scrollbar.has_next_page();
Self { Self {
app_name: Label::new(app_name, Alignment::Center, theme::TEXT_BOLD), app_name: Label::new(app_name, Alignment::Center, theme::TEXT_DEMIBOLD),
account_name: Label::new("".into(), Alignment::Center, theme::TEXT_BOLD), account_name: Label::new("".into(), Alignment::Center, theme::TEXT_DEMIBOLD),
page_swipe, page_swipe,
icon: Child::new(Image::new(icon_data)), icon: Child::new(Image::new(icon_data)),
get_account, get_account,

View File

@ -3,9 +3,8 @@ use crate::ui::{
component::{ component::{
base::ComponentExt, label::Label, text::TextStyle, Child, Component, Event, EventCtx, base::ComponentExt, label::Label, text::TextStyle, Child, Component, Event, EventCtx,
}, },
display::{self, toif::Icon, Color}, display::{self, Color, Font},
geometry::{Alignment, Insets, Offset, Rect}, geometry::{Alignment, Insets, Offset, Rect},
util::icon_text_center,
}; };
pub struct Frame<T, U> { pub struct Frame<T, U> {
@ -55,13 +54,14 @@ where
}) })
} }
pub fn update_content<F>(&mut self, ctx: &mut EventCtx, update_fn: F) pub fn update_content<F, R>(&mut self, ctx: &mut EventCtx, update_fn: F) -> R
where where
F: Fn(&mut T), F: Fn(&mut T) -> R,
{ {
self.content.mutate(ctx, |ctx, c| { self.content.mutate(ctx, |ctx, c| {
update_fn(c); let res = update_fn(c);
c.request_complete_repaint(ctx) c.request_complete_repaint(ctx);
res
}) })
} }
} }
@ -116,7 +116,6 @@ where
pub struct NotificationFrame<T, U> { pub struct NotificationFrame<T, U> {
area: Rect, area: Rect,
icon: Icon,
title: U, title: U,
content: Child<T>, content: Child<T>,
} }
@ -126,15 +125,12 @@ where
T: Component, T: Component,
U: AsRef<str>, U: AsRef<str>,
{ {
const HEIGHT: i16 = 32; const HEIGHT: i16 = 36;
const COLOR: Color = theme::YELLOW; const COLOR: Color = theme::YELLOW;
const TEXT_OFFSET: Offset = Offset::new(1, -2); const BORDER: i16 = 6;
const ICON_SPACE: i16 = 8;
const BORDER: i16 = 8;
pub fn new(icon: Icon, title: U, content: T) -> Self { pub fn new(title: U, content: T) -> Self {
Self { Self {
icon,
title, title,
area: Rect::zero(), area: Rect::zero(),
content: Child::new(content), content: Child::new(content),
@ -145,22 +141,18 @@ where
self.content.inner() self.content.inner()
} }
pub fn paint_notification(area: Rect, icon: Icon, title: &str, color: Color) { pub fn paint_notification(area: Rect, title: &str, color: Color) {
let (area, _) = area let (area, _) = area
.inset(Insets::uniform(Self::BORDER)) .inset(Insets::uniform(Self::BORDER))
.split_top(Self::HEIGHT); .split_top(Self::HEIGHT);
let style = TextStyle { let font = Font::BOLD;
background_color: color,
..theme::TEXT_BOLD
};
display::rect_fill_rounded(area, color, theme::BG, 2); display::rect_fill_rounded(area, color, theme::BG, 2);
icon_text_center( display::text_center(
area.center(), area.center() + Offset::y((font.text_max_height() - font.text_baseline()) / 2),
icon,
Self::ICON_SPACE,
title, title,
style, Font::BOLD,
Self::TEXT_OFFSET, theme::FG,
color,
); );
} }
} }
@ -184,7 +176,7 @@ where
} }
fn paint(&mut self) { fn paint(&mut self) {
Self::paint_notification(self.area, self.icon, self.title.as_ref(), Self::COLOR); Self::paint_notification(self.area, self.title.as_ref(), Self::COLOR);
self.content.paint(); self.content.paint();
} }

View File

@ -22,7 +22,7 @@ use super::{theme, Loader, LoaderMsg};
const AREA: Rect = constant::screen(); const AREA: Rect = constant::screen();
const TOP_CENTER: Point = AREA.top_center(); const TOP_CENTER: Point = AREA.top_center();
const LABEL_Y: i16 = 216; const LABEL_Y: i16 = 222;
const LOCKED_Y: i16 = 107; const LOCKED_Y: i16 = 107;
const TAP_Y: i16 = 134; const TAP_Y: i16 = 134;
const HOLD_Y: i16 = 35; const HOLD_Y: i16 = 35;
@ -181,7 +181,7 @@ where
if self.loader.is_animating() || self.loader.is_completely_grown(Instant::now()) { if self.loader.is_animating() || self.loader.is_completely_grown(Instant::now()) {
self.paint_loader(); self.paint_loader();
} else { } else {
let mut label_style = theme::TEXT_BOLD; let mut label_style = theme::TEXT_DEMIBOLD;
label_style.text_color = theme::FG; label_style.text_color = theme::FG;
let text = HomescreenText { let text = HomescreenText {
@ -262,10 +262,7 @@ where
("LOCKED", "Tap to unlock") ("LOCKED", "Tap to unlock")
}; };
let mut tap_style = theme::TEXT_NORMAL; let mut label_style = theme::TEXT_DEMIBOLD;
tap_style.text_color = theme::OFF_WHITE;
let mut label_style = theme::TEXT_BOLD;
label_style.text_color = theme::GREY_LIGHT; label_style.text_color = theme::GREY_LIGHT;
let texts: [HomescreenText; 3] = [ let texts: [HomescreenText; 3] = [
@ -277,7 +274,7 @@ where
}, },
HomescreenText { HomescreenText {
text: tap, text: tap,
style: tap_style, style: theme::TEXT_NORMAL,
offset: Offset::new(10, TAP_Y), offset: Offset::new(10, TAP_Y),
icon: None, icon: None,
}, },

View File

@ -53,19 +53,20 @@ struct HomescreenTextInfo {
pub const HOMESCREEN_IMAGE_SIZE: i16 = 240; pub const HOMESCREEN_IMAGE_SIZE: i16 = 240;
const HOMESCREEN_MAX_ICON_SIZE: i16 = 20; const HOMESCREEN_MAX_ICON_SIZE: i16 = 20;
const NOTIFICATION_HEIGHT: i16 = 32; const NOTIFICATION_HEIGHT: i16 = 36;
const NOTIFICATION_BORDER: i16 = 8; const NOTIFICATION_BORDER: i16 = 6;
const NOTIFICATION_ICON_SPACE: i16 = 8; const NOTIFICATION_ICON_SPACE: i16 = 8;
const NOTIFICATION_TEXT_OFFSET: Offset = Offset::new(1, -2); const NOTIFICATION_TEXT_OFFSET: Offset = Offset::new(1, -2);
const TEXT_ICON_SPACE: i16 = 2; const TEXT_ICON_SPACE: i16 = 2;
const HOMESCREEN_DIM_HIEGHT: i16 = 30; const HOMESCREEN_DIM_HEIGHT: i16 = 35;
const HOMESCREEN_DIM_START: i16 = 195; const HOMESCREEN_DIM_START: i16 = 198;
const HOMESCREEN_DIM: f32 = 0.85; const HOMESCREEN_DIM: f32 = 0.65;
const HOMESCREEN_DIM_BORDER: i16 = 20; const HOMESCREEN_DIM_BORDER: i16 = theme::BUTTON_SPACING;
const LOCKSCREEN_DIM: f32 = 0.85; const LOCKSCREEN_DIM: f32 = 0.55;
const LOCKSCREEN_DIM_BG: f32 = 0.0; const LOCKSCREEN_DIM_BG: f32 = 0.0;
const LOCKSCREEN_DIM_ALL: bool = true;
const BLUR_SIZE: usize = 9; const BLUR_SIZE: usize = 9;
const BLUR_DIV: u32 = const BLUR_DIV: u32 =
@ -174,14 +175,14 @@ fn homescreen_position_text(
fn homescreen_dim_area(x: i16, y: i16) -> bool { fn homescreen_dim_area(x: i16, y: i16) -> bool {
y >= HOMESCREEN_DIM_START y >= HOMESCREEN_DIM_START
&& (y > HOMESCREEN_DIM_START + 1 && (y > HOMESCREEN_DIM_START + 1
&& y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HIEGHT - 1) && y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT - 1)
&& x > HOMESCREEN_DIM_BORDER && x > HOMESCREEN_DIM_BORDER
&& x < WIDTH - HOMESCREEN_DIM_BORDER) && x < WIDTH - HOMESCREEN_DIM_BORDER)
|| (y > HOMESCREEN_DIM_START || (y > HOMESCREEN_DIM_START
&& y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HIEGHT) && y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT)
&& x > HOMESCREEN_DIM_BORDER + 1 && x > HOMESCREEN_DIM_BORDER + 1
&& x < WIDTH - (HOMESCREEN_DIM_BORDER + 1)) && x < WIDTH - (HOMESCREEN_DIM_BORDER + 1))
|| ((HOMESCREEN_DIM_START..=(HOMESCREEN_DIM_START + HOMESCREEN_DIM_HIEGHT)).contains(&y) || ((HOMESCREEN_DIM_START..=(HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT)).contains(&y)
&& x > HOMESCREEN_DIM_BORDER + 2 && x > HOMESCREEN_DIM_BORDER + 2
&& x < WIDTH - (HOMESCREEN_DIM_BORDER + 2)) && x < WIDTH - (HOMESCREEN_DIM_BORDER + 2))
} }
@ -197,7 +198,7 @@ fn homescreen_line_blurred(
let mut img_buffer = unsafe { get_buffer_16bpp((y & 0x1) as u16, false) }; let mut img_buffer = unsafe { get_buffer_16bpp((y & 0x1) as u16, false) };
for x in 0..HOMESCREEN_IMAGE_SIZE { for x in 0..HOMESCREEN_IMAGE_SIZE {
let c = if homescreen_dim_area(x, y) { let c = if LOCKSCREEN_DIM_ALL {
let x = x as usize; let x = x as usize;
let coef = (65536_f32 * LOCKSCREEN_DIM) as u32; let coef = (65536_f32 * LOCKSCREEN_DIM) as u32;

View File

@ -3,12 +3,13 @@ use crate::ui::{
base::ComponentExt, AuxPageMsg, Component, Event, EventCtx, Never, Pad, PageMsg, Paginate, base::ComponentExt, AuxPageMsg, Component, Event, EventCtx, Never, Pad, PageMsg, Paginate,
}, },
display::{self, Color}, display::{self, Color},
geometry::Rect, geometry::{Insets, Rect},
}; };
use super::{theme, ScrollBar, Swipe, SwipeDirection}; use super::{theme, ScrollBar, Swipe, SwipeDirection};
const SCROLLBAR_HEIGHT: i16 = 32; const SCROLLBAR_HEIGHT: i16 = 18;
const SCROLLBAR_BORDER: i16 = 4;
pub struct HorizontalPage<T> { pub struct HorizontalPage<T> {
content: T, content: T,
@ -75,10 +76,11 @@ where
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
self.swipe.place(bounds); self.swipe.place(bounds);
let (content, scrollbar) = bounds.split_bottom(SCROLLBAR_HEIGHT); let (content, scrollbar) = bounds.split_bottom(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER);
self.pad.place(content); self.pad.place(content);
self.content.place(content); self.content.place(content);
self.scrollbar.place(scrollbar); self.scrollbar
.place(scrollbar.inset(Insets::bottom(SCROLLBAR_BORDER)));
self.scrollbar self.scrollbar
.set_count_and_active_page(self.content.page_count(), 0); .set_count_and_active_page(self.content.page_count(), 0);

View File

@ -215,20 +215,21 @@ impl Bip39Input {
{ {
// Confirm button. // Confirm button.
self.button.enable(ctx); self.button.enable(ctx);
self.button.set_stylesheet(ctx, theme::button_confirm()); self.button.set_stylesheet(ctx, theme::button_pin_confirm());
self.button self.button
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CONFIRM))); .set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_LIST_CHECK)));
} else { } else {
// Auto-complete button. // Auto-complete button.
self.button.enable(ctx); self.button.enable(ctx);
self.button.set_stylesheet(ctx, theme::button_default()); self.button
.set_stylesheet(ctx, theme::button_pin_autocomplete());
self.button self.button
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CLICK))); .set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CLICK)));
} }
} else { } else {
// Disabled button. // Disabled button.
self.button.disable(ctx); self.button.disable(ctx);
self.button.set_stylesheet(ctx, theme::button_default()); self.button.set_stylesheet(ctx, theme::button_pin());
self.button.set_content(ctx, ButtonContent::Text("")); self.button.set_content(ctx, ButtonContent::Text(""));
} }
} }

View File

@ -43,11 +43,13 @@ where
Icon::new(theme::ICON_BACK), Icon::new(theme::ICON_BACK),
Offset::new(30, 17), Offset::new(30, 17),
) )
.styled(theme::button_clear()) .styled(theme::button_reset())
.with_long_press(theme::ERASE_HOLD_DURATION), .with_long_press(theme::ERASE_HOLD_DURATION),
)), )),
input: Child::new(Maybe::hidden(theme::BG, input)), input: Child::new(Maybe::hidden(theme::BG, input)),
keys: T::keys().map(Button::with_text).map(Child::new), keys: T::keys()
.map(|t| Button::with_text(t).styled(theme::button_pin()))
.map(Child::new),
} }
} }
@ -94,8 +96,10 @@ where
type Msg = MnemonicKeyboardMsg; type Msg = MnemonicKeyboardMsg;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
let grid = let (_, bounds) = bounds
Grid::new(bounds.inset(theme::borders()), 4, 3).with_spacing(theme::KEYBOARD_SPACING); .inset(theme::borders())
.split_bottom(4 * theme::MNEMONIC_BUTTON_HEIGHT + 3 * theme::KEYBOARD_SPACING);
let grid = Grid::new(bounds, 4, 3).with_spacing(theme::KEYBOARD_SPACING);
let back_area = grid.row_col(0, 0); let back_area = grid.row_col(0, 0);
let input_area = grid.row_col(0, 1).union(grid.row_col(0, 3)); let input_area = grid.row_col(0, 1).union(grid.row_col(0, 3));

View File

@ -2,13 +2,10 @@ use crate::ui::{
component::{base::ComponentExt, Child, Component, Event, EventCtx, Never}, component::{base::ComponentExt, Child, Component, Event, EventCtx, Never},
display, display,
display::toif::Icon, display::toif::Icon,
geometry::{Grid, Insets, Offset, Rect}, geometry::{Grid, Offset, Rect},
model_tt::component::{ model_tt::component::{
button::{Button, ButtonContent, ButtonMsg}, button::{Button, ButtonContent, ButtonMsg},
keyboard::common::{ keyboard::common::{paint_pending_marker, MultiTapKeyboard, TextBox},
paint_pending_marker, MultiTapKeyboard, TextBox, HEADER_HEIGHT, HEADER_PADDING_BOTTOM,
HEADER_PADDING_SIDE,
},
swipe::{Swipe, SwipeDirection}, swipe::{Swipe, SwipeDirection},
theme, ScrollBar, theme, ScrollBar,
}, },
@ -41,6 +38,7 @@ const KEYBOARD: [[&str; KEY_COUNT]; PAGE_COUNT] = [
]; ];
const MAX_LENGTH: usize = 50; const MAX_LENGTH: usize = 50;
const INPUT_AREA_HEIGHT: i16 = ScrollBar::DOT_SIZE + 9;
impl PassphraseKeyboard { impl PassphraseKeyboard {
pub fn new() -> Self { pub fn new() -> Self {
@ -59,8 +57,9 @@ impl PassphraseKeyboard {
.initially_enabled(false) .initially_enabled(false)
.with_long_press(theme::ERASE_HOLD_DURATION) .with_long_press(theme::ERASE_HOLD_DURATION)
.into_child(), .into_child(),
keys: KEYBOARD[STARTING_PAGE] keys: KEYBOARD[STARTING_PAGE].map(|text| {
.map(|text| Child::new(Button::new(Self::key_content(text)))), Child::new(Button::new(Self::key_content(text)).styled(theme::button_pin()))
}),
scrollbar: ScrollBar::horizontal(), scrollbar: ScrollBar::horizontal(),
fade: false, fade: false,
} }
@ -152,14 +151,13 @@ impl Component for PassphraseKeyboard {
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
let bounds = bounds.inset(theme::borders()); let bounds = bounds.inset(theme::borders());
let (input_area, key_grid_area) = bounds.split_top(HEADER_HEIGHT + HEADER_PADDING_BOTTOM); let (input_area, key_grid_area) =
bounds.split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::BUTTON_SPACING);
let (input_area, scroll_area) = let (input_area, scroll_area) = input_area.split_bottom(INPUT_AREA_HEIGHT);
input_area.split_bottom(ScrollBar::DOT_SIZE + theme::KEYBOARD_SPACING);
let (scroll_area, _) = scroll_area.split_top(ScrollBar::DOT_SIZE); let (scroll_area, _) = scroll_area.split_top(ScrollBar::DOT_SIZE);
let input_area = input_area.inset(Insets::sides(HEADER_PADDING_SIDE));
let key_grid = Grid::new(key_grid_area, 4, 3).with_spacing(theme::KEYBOARD_SPACING); let key_grid = Grid::new(key_grid_area, 4, 3).with_spacing(theme::BUTTON_SPACING);
let confirm_btn_area = key_grid.cell(11); let confirm_btn_area = key_grid.cell(11);
let back_btn_area = key_grid.cell(9); let back_btn_area = key_grid.cell(9);

View File

@ -59,8 +59,8 @@ where
T: AsRef<str>, T: AsRef<str>,
{ {
// Label position fine-tuning. // Label position fine-tuning.
const MAJOR_OFF: Offset = Offset::y(-2); const MAJOR_OFF: Offset = Offset::y(11);
const MINOR_OFF: Offset = Offset::y(-1); const MINOR_OFF: Offset = Offset::y(11);
pub fn new( pub fn new(
major_prompt: T, major_prompt: T,
@ -165,14 +165,14 @@ where
// Prompts and PIN dots display. // Prompts and PIN dots display.
let (header, keypad) = bounds let (header, keypad) = bounds
.inset(borders_no_top) .inset(borders_no_top)
.split_top(theme::borders().top + HEADER_HEIGHT + HEADER_PADDING_BOTTOM); .split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::BUTTON_SPACING);
let prompt = header.inset(HEADER_PADDING); let prompt = header.inset(HEADER_PADDING);
// the inset -3 is a workaround for long text in "re-enter wipe code" // the inset -3 is a workaround for long text in "re-enter wipe code"
let major_area = prompt.translate(Self::MAJOR_OFF).inset(Insets::right(-3)); let major_area = prompt.translate(Self::MAJOR_OFF).inset(Insets::right(-3));
let minor_area = prompt.translate(Self::MINOR_OFF); let minor_area = prompt.translate(Self::MINOR_OFF);
// Control buttons. // Control buttons.
let grid = Grid::new(keypad, 4, 3).with_spacing(theme::KEYBOARD_SPACING); let grid = Grid::new(keypad, 4, 3).with_spacing(theme::BUTTON_SPACING);
// Prompts and PIN dots display. // Prompts and PIN dots display.
self.textbox_pad.place(header); self.textbox_pad.place(header);

View File

@ -224,13 +224,13 @@ impl Slip39Input {
if self.final_word.is_some() { if self.final_word.is_some() {
// Confirm button. // Confirm button.
self.button.enable(ctx); self.button.enable(ctx);
self.button.set_stylesheet(ctx, theme::button_confirm()); self.button.set_stylesheet(ctx, theme::button_pin_confirm());
self.button self.button
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CONFIRM))); .set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_LIST_CHECK)));
} else { } else {
// Disabled button. // Disabled button.
self.button.disable(ctx); self.button.disable(ctx);
self.button.set_stylesheet(ctx, theme::button_default()); self.button.set_stylesheet(ctx, theme::button_pin());
self.button.set_content(ctx, ButtonContent::Text("")); self.button.set_content(ctx, ButtonContent::Text(""));
} }
} }

View File

@ -22,7 +22,7 @@ pub enum SelectWordCountMsg {
impl SelectWordCount { impl SelectWordCount {
pub fn new() -> Self { pub fn new() -> Self {
SelectWordCount { SelectWordCount {
button: LABELS.map(Button::with_text), button: LABELS.map(|t| Button::with_text(t).styled(theme::button_pin())),
} }
} }
} }
@ -31,7 +31,7 @@ impl Component for SelectWordCount {
type Msg = SelectWordCountMsg; type Msg = SelectWordCountMsg;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
let (_, bounds) = bounds.split_bottom(theme::button_rows(2)); let (_, bounds) = bounds.split_bottom(2 * theme::BUTTON_HEIGHT + theme::BUTTON_SPACING);
let grid = Grid::new(bounds, 2, 6).with_spacing(theme::BUTTON_SPACING); let grid = Grid::new(bounds, 2, 6).with_spacing(theme::BUTTON_SPACING);
for (btn, (x, y)) in self.button.iter_mut().zip(CELLS) { for (btn, (x, y)) in self.button.iter_mut().zip(CELLS) {
btn.place(grid.cells(GridCellSpan { btn.place(grid.cells(GridCellSpan {

View File

@ -87,13 +87,12 @@ where
theme::CONTENT_BORDER, theme::CONTENT_BORDER,
)); ));
let grid = Grid::new(button_area, 1, 3).with_spacing(theme::KEYBOARD_SPACING); let grid = Grid::new(button_area, 1, 2).with_spacing(theme::KEYBOARD_SPACING);
self.input.place(input_area); self.input.place(input_area);
self.paragraphs.place(content_area); self.paragraphs.place(content_area);
self.paragraphs_pad.place(content_area); self.paragraphs_pad.place(content_area);
self.info_button.place(grid.row_col(0, 0)); self.info_button.place(grid.row_col(0, 0));
self.confirm_button self.confirm_button.place(grid.row_col(0, 1));
.place(grid.row_col(0, 1).union(grid.row_col(0, 2)));
bounds bounds
} }

View File

@ -368,7 +368,7 @@ where
impl<T> ComponentMsgObj for AddressDetails<T> impl<T> ComponentMsgObj for AddressDetails<T>
where where
T: ParagraphStrType, T: ParagraphStrType + Clone,
{ {
fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result<Obj, Error> { fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result<Obj, Error> {
unreachable!(); unreachable!();
@ -381,7 +381,10 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
let action: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?; let action: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
let description: Option<StrBuffer> = let description: Option<StrBuffer> =
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
let verb: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_verb, "CONFIRM".into())?; let verb: Option<StrBuffer> = kwargs
.get(Qstr::MP_QSTR_verb)
.unwrap_or_else(|_| Obj::const_none())
.try_into_option()?;
let verb_cancel: Option<StrBuffer> = kwargs let verb_cancel: Option<StrBuffer> = kwargs
.get(Qstr::MP_QSTR_verb_cancel) .get(Qstr::MP_QSTR_verb_cancel)
.unwrap_or_else(|_| Obj::const_none()) .unwrap_or_else(|_| Obj::const_none())
@ -396,12 +399,12 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
let mut paragraphs = ParagraphVecShort::new(); let mut paragraphs = ParagraphVecShort::new();
if !reverse { if !reverse {
paragraphs paragraphs
.add(Paragraph::new(&theme::TEXT_BOLD, action)) .add(Paragraph::new(&theme::TEXT_DEMIBOLD, action))
.add(Paragraph::new(&theme::TEXT_NORMAL, description)); .add(Paragraph::new(&theme::TEXT_NORMAL, description));
} else { } else {
paragraphs paragraphs
.add(Paragraph::new(&theme::TEXT_NORMAL, description)) .add(Paragraph::new(&theme::TEXT_NORMAL, description))
.add(Paragraph::new(&theme::TEXT_BOLD, action)); .add(Paragraph::new(&theme::TEXT_DEMIBOLD, action));
} }
paragraphs.into_paragraphs() paragraphs.into_paragraphs()
}; };
@ -440,7 +443,7 @@ fn confirm_blob(
extra: extra.unwrap_or_else(StrBuffer::empty), extra: extra.unwrap_or_else(StrBuffer::empty),
data: data.try_into()?, data: data.try_into()?,
description_font: &theme::TEXT_NORMAL, description_font: &theme::TEXT_NORMAL,
extra_font: &theme::TEXT_BOLD, extra_font: &theme::TEXT_DEMIBOLD,
data_font: &theme::TEXT_MONO, data_font: &theme::TEXT_MONO,
} }
.into_paragraphs(); .into_paragraphs();
@ -452,7 +455,7 @@ fn confirm_blob(
SwipeHoldPage::new(paragraphs, theme::BG), SwipeHoldPage::new(paragraphs, theme::BG),
))? ))?
} else if let Some(verb) = verb { } else if let Some(verb) = verb {
let buttons = Button::cancel_confirm_text(verb_cancel, verb); let buttons = Button::cancel_confirm_text(verb_cancel, Some(verb));
LayoutObj::new(Frame::left_aligned( LayoutObj::new(Frame::left_aligned(
theme::label_title(), theme::label_title(),
title, title,
@ -499,19 +502,14 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
extra: extra.unwrap_or_else(StrBuffer::empty), extra: extra.unwrap_or_else(StrBuffer::empty),
data: data.try_into()?, data: data.try_into()?,
description_font: &theme::TEXT_NORMAL, description_font: &theme::TEXT_NORMAL,
extra_font: &theme::TEXT_BOLD, extra_font: &theme::TEXT_DEMIBOLD,
data_font: &theme::TEXT_MONO, data_font: &theme::TEXT_MONO,
} }
.into_paragraphs(); .into_paragraphs();
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
Button::<&'static str>::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::<&'static str>::with_icon(Icon::new(theme::ICON_CONFIRM))
.styled(theme::button_confirm()),
1,
);
let obj = LayoutObj::new(FloatingButton::top_right_corner( let obj = LayoutObj::new(FloatingButton::top_right_corner(
Icon::new(theme::ICON_INFO_CIRCLE), Icon::new(theme::ICON_CORNER_INFO),
Frame::left_aligned( Frame::left_aligned(
theme::label_title(), theme::label_title(),
title, title,
@ -542,7 +540,7 @@ extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *m
SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG), SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG),
))? ))?
} else { } else {
let buttons = Button::cancel_confirm_text(None, "CONFIRM"); let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
LayoutObj::new(Frame::left_aligned( LayoutObj::new(Frame::left_aligned(
theme::label_title(), theme::label_title(),
title, title,
@ -570,7 +568,7 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m
_ => return Err(Error::ValueError(cstr!("Invalid image."))), _ => return Err(Error::ValueError(cstr!("Invalid image."))),
}; };
let buttons = Button::cancel_confirm_text(None, "CONFIRM"); let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
let obj = LayoutObj::new( let obj = LayoutObj::new(
Frame::centered( Frame::centered(
theme::label_title(), theme::label_title(),
@ -590,33 +588,26 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs:
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let button: StrBuffer = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?; let button: StrBuffer = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?;
let paragraphs = Paragraphs::new(Paragraph::new( let paragraphs = Paragraphs::new([
&theme::TEXT_NORMAL, Paragraph::new(
StrBuffer::from("By continuing you agree\nto Trezor Company's\nterms and conditions."), &theme::TEXT_NORMAL,
)); StrBuffer::from(
let url = FormattedText::new( "By continuing you agree\nto Trezor Company's\nterms and conditions.\r",
theme::TEXT_NORMAL, ),
theme::FORMATTED, ),
"More info at {demibold}trezor.io/tos", Paragraph::new(&theme::TEXT_NORMAL, StrBuffer::from("More info at")),
); Paragraph::new(&theme::TEXT_DEMIBOLD, StrBuffer::from("trezor.io/tos")),
]);
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)), Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text(button).styled(theme::button_confirm()), Button::with_text(button).styled(theme::button_confirm()),
3, true,
); );
let obj = LayoutObj::new( let obj = LayoutObj::new(
Frame::left_aligned( Frame::left_aligned(
theme::label_title(), theme::label_title(),
title, title,
Dialog::new( Dialog::new(paragraphs, buttons),
(
GridPlaced::new(paragraphs)
.with_grid(3, 1)
.with_from_to((0, 0), (1, 0)),
GridPlaced::new(url).with_grid(3, 1).with_row_col(2, 0),
),
buttons,
),
) )
.with_border(theme::borders()), .with_border(theme::borders()),
)?; )?;
@ -635,7 +626,7 @@ extern "C" fn new_show_qr(n_args: usize, args: *const Obj, kwargs: *mut Map) ->
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm(
Button::with_text(verb_cancel), Button::with_text(verb_cancel),
Button::with_text("CONFIRM".into()).styled(theme::button_confirm()), Button::with_text("CONFIRM".into()).styled(theme::button_confirm()),
1, false,
); );
let obj = LayoutObj::new( let obj = LayoutObj::new(
@ -671,7 +662,7 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs:
let obj = LayoutObj::new( let obj = LayoutObj::new(
HorizontalPage::new( HorizontalPage::new(
FloatingButton::top_right_corner(Icon::new(theme::ICON_CANCEL_LARGER), ad), FloatingButton::top_right_corner(Icon::new(theme::ICON_CORNER_CANCEL), ad),
theme::BG, theme::BG,
) )
.with_swipe_right_to_go_back(), .with_swipe_right_to_go_back(),
@ -746,7 +737,7 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs:
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)), Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text("NEXT").styled(theme::button_confirm()), Button::with_text("NEXT").styled(theme::button_confirm()),
2, true,
); );
let obj = LayoutObj::new(Frame::left_aligned( let obj = LayoutObj::new(Frame::left_aligned(
@ -781,7 +772,7 @@ extern "C" fn new_confirm_modify_fee(n_args: usize, args: *const Obj, kwargs: *m
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)), Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text("NEXT").styled(theme::button_confirm()), Button::with_text("NEXT").styled(theme::button_confirm()),
2, true,
); );
let obj = LayoutObj::new(Frame::left_aligned( let obj = LayoutObj::new(Frame::left_aligned(
@ -832,7 +823,7 @@ fn new_show_modal(
Button::cancel_confirm( Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)).styled(theme::button_cancel()), Button::with_icon(Icon::new(theme::ICON_CANCEL)).styled(theme::button_cancel()),
Button::with_text(button).styled(button_style), Button::with_text(button).styled(button_style),
2, true,
), ),
) )
.with_description(description), .with_description(description),
@ -890,7 +881,7 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map
let controls = Button::cancel_confirm( let controls = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)), Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text("CONFIRM").styled(theme::button_confirm()), Button::with_text("CONFIRM").styled(theme::button_confirm()),
2, true,
); );
let fido_page = FidoConfirm::new(app_name, get_page, page_count, icon, controls); let fido_page = FidoConfirm::new(app_name, get_page, page_count, icon, controls);
@ -906,7 +897,7 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map
extern "C" fn new_show_warning(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { extern "C" fn new_show_warning(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| { let block = move |_args: &[Obj], kwargs: &Map| {
let icon = BlendedImage::new( let icon = BlendedImage::new(
Icon::new(theme::IMAGE_BG_TRIANGLE), Icon::new(theme::IMAGE_BG_OCTAGON),
Icon::new(theme::IMAGE_FG_WARN), Icon::new(theme::IMAGE_FG_WARN),
theme::WARN_COLOR, theme::WARN_COLOR,
theme::FG, theme::FG,
@ -952,15 +943,21 @@ extern "C" fn new_show_mismatch() -> Obj {
let url: StrBuffer = "trezor.io/support".into(); let url: StrBuffer = "trezor.io/support".into();
let button = "QUIT"; let button = "QUIT";
let icon = BlendedImage::single(Icon::new(theme::ICON_OCTA), theme::WARN_COLOR, theme::BG); let icon = BlendedImage::new(
Icon::new(theme::IMAGE_BG_OCTAGON),
Icon::new(theme::IMAGE_FG_WARN),
theme::WARN_COLOR,
theme::FG,
theme::BG,
);
let obj = LayoutObj::new( let obj = LayoutObj::new(
IconDialog::new( IconDialog::new(
icon, icon,
title, title,
Button::cancel_confirm_square( Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_BACK)), Button::with_icon(Icon::new(theme::ICON_BACK)),
Button::with_text(button).styled(theme::button_reset()), Button::with_text(button).styled(theme::button_reset()),
true,
), ),
) )
.with_description(description) .with_description(description)
@ -1095,9 +1092,9 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut
let paragraphs = Paragraphs::new([ let paragraphs = Paragraphs::new([
Paragraph::new(&theme::TEXT_NORMAL, "Maximum rounds:".into()), Paragraph::new(&theme::TEXT_NORMAL, "Maximum rounds:".into()),
Paragraph::new(&theme::TEXT_BOLD, max_rounds), Paragraph::new(&theme::TEXT_MONO, max_rounds),
Paragraph::new(&theme::TEXT_NORMAL, "Maximum mining fee:".into()), Paragraph::new(&theme::TEXT_NORMAL, "Maximum mining fee:".into()),
Paragraph::new(&theme::TEXT_BOLD, max_feerate), Paragraph::new(&theme::TEXT_MONO, max_feerate),
]); ]);
let obj = LayoutObj::new(Frame::left_aligned( let obj = LayoutObj::new(Frame::left_aligned(
@ -1162,7 +1159,7 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map)
let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?; let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?;
let words: [StrBuffer; 3] = iter_into_array(words_iterable)?; let words: [StrBuffer; 3] = iter_into_array(words_iterable)?;
let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_NORMAL, description)]); let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]);
let buttons = Button::select_word(words); let buttons = Button::select_word(words);
let obj = LayoutObj::new(Frame::left_aligned( let obj = LayoutObj::new(Frame::left_aligned(
@ -1295,7 +1292,7 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false).unwrap(); let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false).unwrap();
let paragraphs = Paragraphs::new([ let paragraphs = Paragraphs::new([
Paragraph::new(&theme::TEXT_BOLD, title).centered(), Paragraph::new(&theme::TEXT_DEMIBOLD, title).centered(),
Paragraph::new(&theme::TEXT_NORMAL_OFF_WHITE, description).centered(), Paragraph::new(&theme::TEXT_NORMAL_OFF_WHITE, description).centered(),
]) ])
.with_spacing(theme::RECOVERY_SPACING); .with_spacing(theme::RECOVERY_SPACING);
@ -1308,15 +1305,16 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
let obj = if info_button { let obj = if info_button {
LayoutObj::new(NotificationFrame::new( LayoutObj::new(NotificationFrame::new(
Icon::new(theme::ICON_WARN),
notification, notification,
Dialog::new(paragraphs, Button::<&'static str>::abort_info_enter()), Dialog::new(
paragraphs,
Button::cancel_info_confirm("CONTINUE", "MORE INFO"),
),
))? ))?
} else { } else {
LayoutObj::new(NotificationFrame::new( LayoutObj::new(NotificationFrame::new(
Icon::new(theme::ICON_WARN),
notification, notification,
Dialog::new(paragraphs, Button::cancel_confirm_text(None, button)), Dialog::new(paragraphs, Button::cancel_confirm_text(None, Some(button))),
))? ))?
}; };
Ok(obj.into()) Ok(obj.into())
@ -1334,11 +1332,15 @@ extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mu
let title = if dry_run { let title = if dry_run {
"SEED CHECK" "SEED CHECK"
} else { } else {
"RECOVERY MODE" "WALLET RECOVERY"
}; };
let paragraphs = Paragraphs::new( let paragraphs = Paragraphs::new(
Paragraph::new(&theme::TEXT_BOLD, StrBuffer::from("Number of words?")).centered(), Paragraph::new(
&theme::TEXT_DEMIBOLD,
StrBuffer::from("Select number of words in your recovery seed."),
)
.centered(),
); );
let obj = LayoutObj::new( let obj = LayoutObj::new(
@ -1384,7 +1386,7 @@ extern "C" fn new_show_remaining_shares(n_args: usize, args: *const Obj, kwargs:
for page in iter { for page in iter {
let [title, description]: [StrBuffer; 2] = iter_into_array(page)?; let [title, description]: [StrBuffer; 2] = iter_into_array(page)?;
paragraphs paragraphs
.add(Paragraph::new(&theme::TEXT_BOLD, title)) .add(Paragraph::new(&theme::TEXT_DEMIBOLD, title))
.add(Paragraph::new(&theme::TEXT_NORMAL, description).break_after()); .add(Paragraph::new(&theme::TEXT_NORMAL, description).break_after());
} }
@ -1915,7 +1917,7 @@ mod tests {
#[test] #[test]
fn trace_example_layout() { fn trace_example_layout() {
let buttons = let buttons =
Button::cancel_confirm(Button::with_text("Left"), Button::with_text("Right"), 1); Button::cancel_confirm(Button::with_text("Left"), Button::with_text("Right"), false);
let mut layout = Dialog::new( let mut layout = Dialog::new(
FormattedText::new( FormattedText::new(
theme::TEXT_NORMAL, theme::TEXT_NORMAL,

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More