mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-21 12:02:19 +00:00
feat(core): word quiz enter animation
[no changelog]
This commit is contained in:
parent
6ad41aa06e
commit
2f6ade5911
@ -7,7 +7,7 @@ use crate::trezorhal::time;
|
|||||||
|
|
||||||
const MILLIS_PER_SEC: u32 = 1000;
|
const MILLIS_PER_SEC: u32 = 1000;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
pub struct Duration {
|
pub struct Duration {
|
||||||
millis: u32,
|
millis: u32,
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,10 @@ use crate::{
|
|||||||
strutil::TString,
|
strutil::TString,
|
||||||
time::{Duration, Stopwatch},
|
time::{Duration, Stopwatch},
|
||||||
ui::{
|
ui::{
|
||||||
component::{base::Component, Event, EventCtx},
|
component::{
|
||||||
|
base::{AttachType, Component},
|
||||||
|
Event, EventCtx, SwipeDirection,
|
||||||
|
},
|
||||||
constant::screen,
|
constant::screen,
|
||||||
display::{Color, Icon},
|
display::{Color, Icon},
|
||||||
geometry::{Offset, Rect},
|
geometry::{Offset, Rect},
|
||||||
@ -39,19 +42,19 @@ type AreasForSeparators = Vec<Rect, N_SEPS>;
|
|||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
struct AttachAnimation {
|
struct AttachAnimation {
|
||||||
|
pub attach_top: bool,
|
||||||
pub timer: Stopwatch,
|
pub timer: Stopwatch,
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
|
pub duration: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttachAnimation {
|
impl AttachAnimation {
|
||||||
const DURATION_MS: u32 = 350;
|
|
||||||
fn is_active(&self) -> bool {
|
fn is_active(&self) -> bool {
|
||||||
if animation_disabled() {
|
if animation_disabled() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.timer
|
self.timer.is_running_within(self.duration)
|
||||||
.is_running_within(Duration::from_millis(Self::DURATION_MS))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self) -> f32 {
|
fn eval(&self) -> f32 {
|
||||||
@ -63,25 +66,69 @@ impl AttachAnimation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_offset(&self, t: f32) -> Offset {
|
fn get_offset(&self, t: f32) -> Offset {
|
||||||
let value = pareen::constant(0.0).seq_ease_in(
|
let value = if self.attach_top {
|
||||||
0.0,
|
1.0
|
||||||
easer::functions::Cubic,
|
} else {
|
||||||
Self::DURATION_MS as f32 / 1000.0,
|
pareen::constant(0.0)
|
||||||
pareen::constant(1.0),
|
.seq_ease_in(
|
||||||
);
|
0.0,
|
||||||
|
easer::functions::Cubic,
|
||||||
|
self.duration.to_millis() as f32 / 1000.0,
|
||||||
|
pareen::constant(1.0).eval(t),
|
||||||
|
)
|
||||||
|
.eval(t)
|
||||||
|
};
|
||||||
|
|
||||||
Offset::lerp(Offset::new(-40, 0), Offset::zero(), value.eval(t))
|
Offset::lerp(Offset::new(-40, 0), Offset::zero(), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mask_width(&self, t: f32) -> i16 {
|
fn get_mask_width(&self, t: f32) -> i16 {
|
||||||
let value = pareen::constant(0.0).seq_ease_in(
|
let value = if self.attach_top {
|
||||||
0.0,
|
1.0
|
||||||
easer::functions::Circ,
|
} else {
|
||||||
0.15,
|
pareen::constant(0.0)
|
||||||
pareen::constant(1.0),
|
.seq_ease_in(0.0, easer::functions::Circ, 0.15, pareen::constant(1.0))
|
||||||
);
|
.eval(t)
|
||||||
|
};
|
||||||
|
|
||||||
//todo screen here is incorrect
|
//todo screen here is incorrect
|
||||||
i16::lerp(screen().width(), 0, value.eval(t))
|
i16::lerp(screen().width(), 0, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mask_item1_opacity(&self, t: f32) -> u8 {
|
||||||
|
let value = if self.attach_top {
|
||||||
|
pareen::constant(0.0)
|
||||||
|
.seq_ease_in(0.0, easer::functions::Cubic, 0.15, pareen::constant(1.0))
|
||||||
|
.eval(t)
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
|
||||||
|
u8::lerp(255, 0, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mask_item2_opacity(&self, t: f32) -> u8 {
|
||||||
|
let value = if self.attach_top {
|
||||||
|
pareen::constant(0.0)
|
||||||
|
.seq_ease_in(0.1, easer::functions::Cubic, 0.15, pareen::constant(1.0))
|
||||||
|
.eval(t)
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
|
||||||
|
u8::lerp(255, 0, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mask_item3_opacity(&self, t: f32) -> u8 {
|
||||||
|
let value = if self.attach_top {
|
||||||
|
pareen::constant(0.0)
|
||||||
|
.seq_ease_in(0.2, easer::functions::Cubic, 0.15, pareen::constant(1.0))
|
||||||
|
.eval(t)
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
|
||||||
|
u8::lerp(255, 0, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&mut self) {
|
fn start(&mut self) {
|
||||||
@ -96,6 +143,15 @@ impl AttachAnimation {
|
|||||||
|
|
||||||
fn lazy_start(&mut self, ctx: &mut EventCtx, event: Event) {
|
fn lazy_start(&mut self, ctx: &mut EventCtx, event: Event) {
|
||||||
if let Event::Attach(_) = event {
|
if let Event::Attach(_) = event {
|
||||||
|
if let Event::Attach(AttachType::Swipe(SwipeDirection::Up))
|
||||||
|
| Event::Attach(AttachType::Swipe(SwipeDirection::Down))
|
||||||
|
| Event::Attach(AttachType::Initial) = event
|
||||||
|
{
|
||||||
|
self.attach_top = true;
|
||||||
|
self.duration = Duration::from_millis(350);
|
||||||
|
} else {
|
||||||
|
self.duration = Duration::from_millis(350);
|
||||||
|
}
|
||||||
self.reset();
|
self.reset();
|
||||||
ctx.request_anim_frame();
|
ctx.request_anim_frame();
|
||||||
}
|
}
|
||||||
@ -213,17 +269,34 @@ impl Component for VerticalMenu {
|
|||||||
|
|
||||||
let offset = self.attach_animation.get_offset(t);
|
let offset = self.attach_animation.get_offset(t);
|
||||||
let mask_width = self.attach_animation.get_mask_width(t);
|
let mask_width = self.attach_animation.get_mask_width(t);
|
||||||
|
let item1_opacity = self.attach_animation.get_mask_item1_opacity(t);
|
||||||
|
let item2_opacity = self.attach_animation.get_mask_item2_opacity(t);
|
||||||
|
let item3_opacity = self.attach_animation.get_mask_item3_opacity(t);
|
||||||
|
|
||||||
|
let opacities = [item1_opacity, item2_opacity, item3_opacity];
|
||||||
|
|
||||||
target.with_origin(offset, &|target| {
|
target.with_origin(offset, &|target| {
|
||||||
// render buttons separated by thin bars
|
// render buttons separated by thin bars
|
||||||
for button in &self.buttons {
|
for (i, button) in (&self.buttons).into_iter().enumerate() {
|
||||||
button.render(target);
|
button.render(target);
|
||||||
|
|
||||||
|
Bar::new(button.area())
|
||||||
|
.with_fg(Color::black())
|
||||||
|
.with_bg(Color::black())
|
||||||
|
.with_alpha(opacities[i])
|
||||||
|
.render(target);
|
||||||
}
|
}
|
||||||
for area in self.areas_sep.iter() {
|
for (i, area) in self.areas_sep.iter().enumerate() {
|
||||||
Bar::new(*area)
|
Bar::new(*area)
|
||||||
.with_thickness(MENU_SEP_HEIGHT)
|
.with_thickness(MENU_SEP_HEIGHT)
|
||||||
.with_fg(theme::GREY_EXTRA_DARK)
|
.with_fg(theme::GREY_EXTRA_DARK)
|
||||||
.render(target);
|
.render(target);
|
||||||
|
|
||||||
|
Bar::new(*area)
|
||||||
|
.with_fg(Color::black())
|
||||||
|
.with_bg(Color::black())
|
||||||
|
.with_alpha(opacities[i])
|
||||||
|
.render(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo screen here is incorrect
|
// todo screen here is incorrect
|
||||||
|
Loading…
Reference in New Issue
Block a user