You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/rust/src/ui/model_tt/component/coinjoin_progress.rs

141 lines
3.9 KiB

use core::mem;
use crate::{
error::Error,
maybe_trace::MaybeTrace,
strutil::TString,
translations::TR,
ui::{
component::{
base::Never, painter, Child, Component, ComponentExt, Empty, Event, EventCtx, Label,
Split,
},
display::loader::{loader_circular_uncompress, LoaderDimensions},
geometry::{Insets, Rect},
util::animation_disabled,
},
};
use super::{theme, Frame};
const RECTANGLE_HEIGHT: i16 = 56;
const LABEL_TOP: i16 = 135;
const LOADER_OUTER: i16 = 39;
const LOADER_INNER: i16 = 28;
const LOADER_OFFSET: i16 = -34;
const LOADER_SPEED: u16 = 5;
pub struct CoinJoinProgress<U> {
value: u16,
indeterminate: bool,
content: Child<Frame<Split<Empty, U>>>,
// Label is not a child since circular loader paints large black rectangle which overlaps it.
// To work around this, draw label every time loader is drawn.
label: Label<'static>,
}
impl<U> CoinJoinProgress<U> {
pub fn new(
text: TString<'static>,
indeterminate: bool,
) -> Result<CoinJoinProgress<impl Component<Msg = Never> + MaybeTrace>, Error> {
let style = theme::label_coinjoin_progress();
let label = Label::centered(
TryInto::<TString>::try_into(TR::coinjoin__title_do_not_disconnect)?,
style,
)
.vertically_centered();
let bg = painter::rect_painter(style.background_color, theme::BG);
let inner = (bg, label);
CoinJoinProgress::with_background(text, inner, indeterminate)
}
}
impl<U> CoinJoinProgress<U>
where
U: Component<Msg = Never>,
{
pub fn with_background(
text: TString<'static>,
inner: U,
indeterminate: bool,
) -> Result<Self, Error> {
Ok(Self {
value: 0,
indeterminate,
content: Frame::centered(
theme::label_title(),
TR::coinjoin__title_progress.try_into()?,
Split::bottom(RECTANGLE_HEIGHT, 0, Empty, inner),
)
.into_child(),
label: Label::centered(text, theme::TEXT_NORMAL),
})
}
}
impl<U> Component for CoinJoinProgress<U>
where
U: Component<Msg = Never>,
{
type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect {
self.content.place(bounds);
let label_bounds = bounds.inset(Insets::top(LABEL_TOP));
self.label.place(label_bounds);
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
self.content.event(ctx, event);
self.label.event(ctx, event);
match event {
_ if animation_disabled() => {
return None;
}
Event::Attach if self.indeterminate => {
ctx.request_anim_frame();
}
Event::Timer(EventCtx::ANIM_FRAME_TIMER) => {
self.value = (self.value + LOADER_SPEED) % 1000;
ctx.request_anim_frame();
ctx.request_paint();
}
Event::Progress(new_value, _new_description) => {
if mem::replace(&mut self.value, new_value) != new_value {
ctx.request_paint();
}
}
_ => {}
}
None
}
fn paint(&mut self) {
self.content.paint();
loader_circular_uncompress(
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
LOADER_OFFSET,
theme::FG,
theme::BG,
self.value,
self.indeterminate,
None,
);
self.label.paint();
}
}
#[cfg(feature = "ui_debug")]
impl<U> crate::trace::Trace for CoinJoinProgress<U>
where
U: Component + crate::trace::Trace,
{
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("CoinJoinProgress");
t.child("label", &self.label);
t.child("content", &self.content);
}
}